Improve SaferCallerImplTest (#2922)

Failed to to unnecessary stubbing exception in https://ci.openhab.org/job/PR-openHAB-Core/4556/

Also removes unnecessary code.

Signed-off-by: Jan N. Klug <github@klug.nrw>
pull/2927/head
J-N-K 2022-04-22 10:52:28 +02:00 committed by GitHub
parent 0e7e7a37b7
commit ee7095d96d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 94 additions and 148 deletions

View File

@ -12,8 +12,8 @@
*/ */
package org.openhab.core.internal.common; package org.openhab.core.internal.common;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.isA; import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@ -46,6 +46,8 @@ import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.openhab.core.JavaTest; import org.openhab.core.JavaTest;
import org.openhab.core.common.QueueingThreadPoolExecutor; import org.openhab.core.common.QueueingThreadPoolExecutor;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -56,6 +58,7 @@ import org.slf4j.LoggerFactory;
* @author Simon Kaufmann - Initial contribution and API. * @author Simon Kaufmann - Initial contribution and API.
*/ */
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
@NonNullByDefault @NonNullByDefault
public class SafeCallerImplTest extends JavaTest { public class SafeCallerImplTest extends JavaTest {
@ -81,8 +84,9 @@ public class SafeCallerImplTest extends JavaTest {
private @NonNullByDefault({}) @Mock Runnable timeoutHandlerMock; private @NonNullByDefault({}) @Mock Runnable timeoutHandlerMock;
private @NonNullByDefault({}) @Mock Consumer<Throwable> errorHandlerMock; private @NonNullByDefault({}) @Mock Consumer<Throwable> errorHandlerMock;
public static interface ITarget { @FunctionalInterface
public String method(); public interface ITarget {
String method();
} }
public static class Target implements ITarget { public static class Target implements ITarget {
@ -108,8 +112,8 @@ public class SafeCallerImplTest extends JavaTest {
} }
}; };
assertTrue(BLOCK > TIMEOUT + GRACE); assertThat(BLOCK, is(greaterThan(TIMEOUT + GRACE)));
assertTrue(GRACE < TIMEOUT); assertThat(GRACE, is(lessThan(TIMEOUT)));
} }
@AfterEach @AfterEach
@ -122,49 +126,44 @@ public class SafeCallerImplTest extends JavaTest {
} }
@Test @Test
public void testSimpleCall() throws Exception { public void testSimpleCall() {
Target target = new Target(); Target target = new Target();
String result = safeCaller.create(target, ITarget.class).build().method(); String result = safeCaller.create(target, ITarget.class).build().method();
assertThat(result, is("Hello")); assertThat(result, is("Hello"));
} }
@Test @Test
public void testInterfaceDetection() throws Exception { public void testInterfaceDetection() {
ITarget target = new Target(); ITarget target = new Target();
String result = safeCaller.create(target, ITarget.class).build().method(); String result = safeCaller.create(target, ITarget.class).build().method();
assertThat(result, is("Hello")); assertThat(result, is("Hello"));
} }
@Test @Test
public void testExceptionHandler() throws Exception { public void testExceptionHandler() {
Runnable mock = mock(Runnable.class); Runnable mock = mock(Runnable.class);
doThrow(RuntimeException.class).when(mock).run(); doThrow(RuntimeException.class).when(mock).run();
safeCaller.create(mock, Runnable.class).onException(errorHandlerMock).build().run(); safeCaller.create(mock, Runnable.class).onException(errorHandlerMock).build().run();
waitForAssert(() -> { waitForAssert(() -> verify(errorHandlerMock).accept(isA(Throwable.class)));
verify(errorHandlerMock).accept(isA(Throwable.class));
});
} }
@Test @Test
public void testTimeoutHandler() throws Exception { public void testTimeoutHandler() {
Runnable mock = mock(Runnable.class); Runnable mock = mock(Runnable.class);
doAnswer(a -> sleep(BLOCK)).when(mock).run(); doAnswer(a -> sleep(BLOCK)).when(mock).run();
safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT).onTimeout(timeoutHandlerMock).build().run(); safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT).onTimeout(timeoutHandlerMock).build().run();
waitForAssert(() -> { waitForAssert(() -> verify(timeoutHandlerMock).run());
verify(timeoutHandlerMock).run();
});
} }
@Test @Test
public void testTimeoutReturnsEarly() throws Exception { public void testTimeoutReturnsEarly() {
Runnable mock = mock(Runnable.class); Runnable mock = mock(Runnable.class);
doAnswer(a -> sleep(BLOCK)).when(mock).run(); doAnswer(a -> sleep(BLOCK)).when(mock).run();
assertDurationBetween(TIMEOUT - GRACE, BLOCK - GRACE, () -> { assertDurationBetween(TIMEOUT - GRACE, BLOCK - GRACE,
safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT).build().run(); () -> safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT).build().run());
});
} }
@Test @Test
@ -172,141 +171,104 @@ public class SafeCallerImplTest extends JavaTest {
Runnable mock = mock(Runnable.class); Runnable mock = mock(Runnable.class);
doAnswer(a -> sleep(BLOCK)).when(mock).run(); doAnswer(a -> sleep(BLOCK)).when(mock).run();
spawn(() -> { spawn(() -> assertDurationBetween(TIMEOUT - GRACE, BLOCK - GRACE,
assertDurationBetween(TIMEOUT - GRACE, BLOCK - GRACE, () -> { () -> safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT).build().run()));
safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT).build().run();
});
});
sleep(GRACE); // give it a chance to start sleep(GRACE); // give it a chance to start
spawn(() -> { spawn(() -> assertDurationBetween(TIMEOUT - GRACE, BLOCK - GRACE,
assertDurationBetween(TIMEOUT - GRACE, BLOCK - GRACE, () -> { () -> safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT).build().run()));
safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT).build().run(); waitForAssert(() -> verify(mock, times(2)).run());
});
});
waitForAssert(() -> {
verify(mock, times(2)).run();
});
} }
@Test @Test
public void testSingleThreadSyncSecondCallWhileInTimeout() throws Exception { public void testSingleThreadSyncSecondCallWhileInTimeout() {
Runnable mock = mock(Runnable.class); Runnable mock = mock(Runnable.class);
doAnswer(a -> sleep(BLOCK)).when(mock).run(); doAnswer(a -> sleep(BLOCK)).when(mock).run();
configureSingleThread(); configureSingleThread();
assertDurationBetween(TIMEOUT - GRACE, BLOCK - GRACE, () -> { assertDurationBetween(TIMEOUT - GRACE, BLOCK - GRACE,
safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT).build().run(); () -> safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT).build().run());
}); assertDurationBelow(2 * GRACE,
assertDurationBelow(2 * GRACE, () -> { () -> safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT).build().run());
safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT).build().run(); assertDurationBetween(TIMEOUT - GRACE, BLOCK + GRACE, () -> waitForAssert(() -> verify(mock, times(2)).run()));
});
assertDurationBetween(TIMEOUT - GRACE, BLOCK + GRACE, () -> {
waitForAssert(() -> {
verify(mock, times(2)).run();
});
});
} }
@Test @Test
public void testSingleThreadSyncParallel() throws Exception { public void testSingleThreadSyncParallel() {
Runnable mock = mock(Runnable.class); Runnable mock = mock(Runnable.class);
doAnswer(a -> sleep(BLOCK)).when(mock).run(); doAnswer(a -> sleep(BLOCK)).when(mock).run();
configureSingleThread(); configureSingleThread();
spawn(() -> { spawn(() -> assertDurationBetween(0, BLOCK - GRACE,
assertDurationBetween(0, BLOCK - GRACE, () -> { () -> safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT).build().run()));
safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT).build().run();
});
});
sleep(GRACE); // give it a chance to start sleep(GRACE); // give it a chance to start
spawn(() -> { spawn(() -> assertDurationBelow(3 * GRACE,
assertDurationBelow(3 * GRACE, () -> { () -> safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT).build().run()));
safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT).build().run(); assertDurationBetween(BLOCK - 2 * GRACE, BLOCK + TIMEOUT + 4 * GRACE,
}); () -> waitForAssert(() -> verify(mock, times(2)).run()));
});
assertDurationBetween(BLOCK - 2 * GRACE, BLOCK + TIMEOUT + 4 * GRACE, () -> {
waitForAssert(() -> {
verify(mock, times(2)).run();
});
});
} }
@Test @Test
public void testMultiThreadAsync() throws Exception { public void testMultiThreadAsync() {
Runnable mock = mock(Runnable.class); Runnable mock = mock(Runnable.class);
doAnswer(a -> sleep(TIMEOUT)).when(mock).run(); doAnswer(a -> sleep(TIMEOUT)).when(mock).run();
assertDurationBelow(GRACE, () -> { assertDurationBelow(GRACE,
safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT).withAsync().build().run(); () -> safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT).withAsync().build().run());
}); assertDurationBelow(GRACE,
assertDurationBelow(GRACE, () -> { () -> safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT).withAsync().build().run());
safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT).withAsync().build().run(); waitForAssert(() -> verify(mock, times(2)).run());
});
waitForAssert(() -> {
verify(mock, times(2)).run();
});
} }
@Test @Test
public void testSingleThreadAsync() throws Exception { public void testSingleThreadAsync() {
Runnable mock = mock(Runnable.class); Runnable mock = mock(Runnable.class);
doAnswer(a -> sleep(BLOCK)).when(mock).run(); doAnswer(a -> sleep(BLOCK)).when(mock).run();
configureSingleThread(); configureSingleThread();
assertDurationBelow(GRACE, () -> { assertDurationBelow(GRACE,
safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT).withAsync().build().run(); () -> safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT).withAsync().build().run());
}); assertDurationBelow(GRACE,
assertDurationBelow(GRACE, () -> { () -> safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT).withAsync().build().run());
safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT).withAsync().build().run(); waitForAssert(() -> verify(mock, times(2)).run());
});
waitForAssert(() -> {
verify(mock, times(2)).run();
});
} }
@Test @Test
public void testSecondCallGetsRefusedSameIdentifier() throws Exception { public void testSecondCallGetsRefusedSameIdentifier() {
Runnable mock1 = mock(Runnable.class); Runnable mock1 = mock(Runnable.class);
doAnswer(a -> sleep(BLOCK)).when(mock1).run(); doAnswer(a -> sleep(BLOCK)).when(mock1).run();
Runnable mock2 = mock(Runnable.class); Runnable mock2 = mock(Runnable.class);
assertDurationBetween(TIMEOUT - GRACE, BLOCK - GRACE, () -> { assertDurationBetween(TIMEOUT - GRACE, BLOCK - GRACE,
safeCaller.create(mock1, Runnable.class).withTimeout(TIMEOUT).withIdentifier("id").build().run(); () -> safeCaller.create(mock1, Runnable.class).withTimeout(TIMEOUT).withIdentifier("id").build().run());
}); assertDurationBelow(4 * GRACE,
assertDurationBelow(4 * GRACE, () -> { () -> safeCaller.create(mock2, Runnable.class).withTimeout(TIMEOUT).withIdentifier("id").build().run());
safeCaller.create(mock2, Runnable.class).withTimeout(TIMEOUT).withIdentifier("id").build().run();
});
} }
@Test @Test
public void testSecondCallGetsAcceptedDifferentIdentifier() throws Exception { public void testSecondCallGetsAcceptedDifferentIdentifier() {
Runnable mock1 = mock(Runnable.class); Runnable mock1 = mock(Runnable.class);
doAnswer(a -> sleep(BLOCK)).when(mock1).run(); doAnswer(a -> sleep(BLOCK)).when(mock1).run();
Runnable mock2 = mock(Runnable.class); Runnable mock2 = mock(Runnable.class);
doAnswer(a -> sleep(BLOCK)).when(mock2).run(); doAnswer(a -> sleep(BLOCK)).when(mock2).run();
assertDurationBetween(TIMEOUT - GRACE, BLOCK - GRACE, () -> { assertDurationBetween(TIMEOUT - GRACE, BLOCK - GRACE, () -> safeCaller.create(mock1, Runnable.class)
safeCaller.create(mock1, Runnable.class).withTimeout(TIMEOUT).withIdentifier(new Object()).build().run(); .withTimeout(TIMEOUT).withIdentifier(new Object()).build().run());
}); assertDurationBetween(TIMEOUT - GRACE, BLOCK - GRACE, () -> safeCaller.create(mock2, Runnable.class)
assertDurationBetween(TIMEOUT - GRACE, BLOCK - GRACE, () -> { .withTimeout(TIMEOUT).withIdentifier(new Object()).build().run());
safeCaller.create(mock2, Runnable.class).withTimeout(TIMEOUT).withIdentifier(new Object()).build().run();
});
} }
@Test @Test
public void testTimeoutConfiguration() throws Exception { public void testTimeoutConfiguration() {
Runnable mock = mock(Runnable.class); Runnable mock = mock(Runnable.class);
doAnswer(a -> sleep(BLOCK)).when(mock).run(); doAnswer(a -> sleep(BLOCK)).when(mock).run();
assertDurationAbove(BLOCK - GRACE, () -> { assertDurationAbove(BLOCK - GRACE, () -> safeCaller.create(mock, Runnable.class).withTimeout(BLOCK + GRACE * 2)
safeCaller.create(mock, Runnable.class).withTimeout(BLOCK + GRACE * 2).onTimeout(timeoutHandlerMock).build() .onTimeout(timeoutHandlerMock).build().run());
.run();
});
verifyNoMoreInteractions(timeoutHandlerMock); verifyNoMoreInteractions(timeoutHandlerMock);
} }
@Test @Test
public void testCallWrapped() throws Exception { public void testCallWrapped() {
AtomicReference<String> outerThreadName = new AtomicReference<>(); AtomicReference<String> outerThreadName = new AtomicReference<>();
AtomicReference<String> middleThreadName = new AtomicReference<>(); AtomicReference<String> middleThreadName = new AtomicReference<>();
AtomicReference<String> innerThreadName = new AtomicReference<>(); AtomicReference<String> innerThreadName = new AtomicReference<>();
@ -315,13 +277,13 @@ public class SafeCallerImplTest extends JavaTest {
@Override @Override
public void run() { public void run() {
outerThreadName.set(Thread.currentThread().getName()); outerThreadName.set(Thread.currentThread().getName());
safeCaller.create((Runnable) () -> { safeCaller.create(() -> {
}, Runnable.class).build().run(); }, Runnable.class).build().run();
safeCaller.create(new Runnable() { safeCaller.create(new Runnable() {
@Override @Override
public void run() { public void run() {
middleThreadName.set(Thread.currentThread().getName()); middleThreadName.set(Thread.currentThread().getName());
safeCaller.create((Runnable) () -> { safeCaller.create(() -> {
}, Runnable.class).build().run(); }, Runnable.class).build().run();
safeCaller.create(new Runnable() { safeCaller.create(new Runnable() {
@Override @Override
@ -357,6 +319,7 @@ public class SafeCallerImplTest extends JavaTest {
} }
@Test @Test
@SuppressWarnings("unchecked")
public void testLambdas() throws Exception { public void testLambdas() throws Exception {
ITarget thingHandler = new Target(); ITarget thingHandler = new Target();
@ -365,9 +328,7 @@ public class SafeCallerImplTest extends JavaTest {
return null; return null;
}, Callable.class).build().call(); }, Callable.class).build().call();
safeCaller.create(() -> { safeCaller.create(thingHandler::method, Runnable.class).build().run();
thingHandler.method();
}, Runnable.class).build().run();
Object res = safeCaller.create((Function<String, String>) name -> ("Hello " + name + "!"), Function.class) Object res = safeCaller.create((Function<String, String>) name -> ("Hello " + name + "!"), Function.class)
.build().apply("World"); .build().apply("World");
@ -375,40 +336,35 @@ public class SafeCallerImplTest extends JavaTest {
} }
@Test @Test
public void testAsyncReturnsImmediately() throws Exception { public void testAsyncReturnsImmediately() {
Runnable mock1 = mock(Runnable.class); Runnable mock1 = mock(Runnable.class);
doAnswer(a -> sleep(BLOCK)).when(mock1).run(); doAnswer(a -> sleep(BLOCK)).when(mock1).run();
assertDurationBelow(GRACE, () -> { assertDurationBelow(GRACE,
safeCaller.create(mock1, Runnable.class).withTimeout(TIMEOUT).withAsync().build().run(); () -> safeCaller.create(mock1, Runnable.class).withTimeout(TIMEOUT).withAsync().build().run());
});
waitForAssert(() -> verify(mock1, timeout(1000).times(1)).run()); waitForAssert(() -> verify(mock1, timeout(1000).times(1)).run());
} }
@Test @Test
public void testAsyncTimeoutHandler() throws Exception { public void testAsyncTimeoutHandler() {
Object identifier = new Object(); Object identifier = new Object();
Runnable mock1 = mock(Runnable.class); Runnable mock1 = mock(Runnable.class);
doAnswer(a -> sleep(BLOCK)).when(mock1).run(); doAnswer(a -> sleep(BLOCK)).when(mock1).run();
assertDurationBelow(GRACE, () -> { assertDurationBelow(GRACE, () -> safeCaller.create(mock1, Runnable.class).withTimeout(TIMEOUT).withAsync()
safeCaller.create(mock1, Runnable.class).withTimeout(TIMEOUT).withAsync().withIdentifier(identifier) .withIdentifier(identifier).onTimeout(timeoutHandlerMock).onException(errorHandlerMock).build().run());
.onTimeout(timeoutHandlerMock).onException(errorHandlerMock).build().run();
});
waitForAssert(() -> verify(mock1, times(1)).run()); waitForAssert(() -> verify(mock1, times(1)).run());
waitForAssert(() -> verify(timeoutHandlerMock, times(1)).run()); waitForAssert(() -> verify(timeoutHandlerMock, times(1)).run());
verifyNoMoreInteractions(errorHandlerMock); verifyNoMoreInteractions(errorHandlerMock);
} }
@Test @Test
public void testAsyncExceptionHandler() throws Exception { public void testAsyncExceptionHandler() {
Object identifier = new Object(); Object identifier = new Object();
Runnable mock1 = mock(Runnable.class); Runnable mock1 = mock(Runnable.class);
doThrow(RuntimeException.class).when(mock1).run(); doThrow(RuntimeException.class).when(mock1).run();
assertDurationBelow(2 * GRACE, () -> { assertDurationBelow(2 * GRACE, () -> safeCaller.create(mock1, Runnable.class).withTimeout(TIMEOUT).withAsync()
safeCaller.create(mock1, Runnable.class).withTimeout(TIMEOUT).withAsync().withIdentifier(identifier) .withIdentifier(identifier).onTimeout(timeoutHandlerMock).onException(errorHandlerMock).build().run());
.onTimeout(timeoutHandlerMock).onException(errorHandlerMock).build().run();
});
waitForAssert(() -> verify(mock1, times(1)).run()); waitForAssert(() -> verify(mock1, times(1)).run());
waitForAssert(() -> verify(errorHandlerMock, times(1)).accept(isA(Exception.class))); waitForAssert(() -> verify(errorHandlerMock, times(1)).accept(isA(Exception.class)));
verifyNoMoreInteractions(errorHandlerMock); verifyNoMoreInteractions(errorHandlerMock);
@ -416,7 +372,7 @@ public class SafeCallerImplTest extends JavaTest {
} }
@Test @Test
public void testAsyncDoesNotTimeoutDifferentIdentifiers() throws Exception { public void testAsyncDoesNotTimeoutDifferentIdentifiers() {
Runnable mock1 = mock(Runnable.class); Runnable mock1 = mock(Runnable.class);
doAnswer(a -> sleep(BLOCK)).when(mock1).run(); doAnswer(a -> sleep(BLOCK)).when(mock1).run();
Runnable mock2 = mock(Runnable.class); Runnable mock2 = mock(Runnable.class);
@ -435,7 +391,7 @@ public class SafeCallerImplTest extends JavaTest {
} }
@Test @Test
public void testAsyncDoesNotTimeoutDefaultIdentifiers() throws Exception { public void testAsyncDoesNotTimeoutDefaultIdentifiers() {
Runnable mock1 = mock(Runnable.class); Runnable mock1 = mock(Runnable.class);
doAnswer(a -> sleep(BLOCK)).when(mock1).run(); doAnswer(a -> sleep(BLOCK)).when(mock1).run();
Runnable mock2 = mock(Runnable.class); Runnable mock2 = mock(Runnable.class);
@ -451,7 +407,7 @@ public class SafeCallerImplTest extends JavaTest {
} }
@Test @Test
public void testAsyncRunsSubsequentAndDoesNotTimeoutSameIdentifier() throws Exception { public void testAsyncRunsSubsequentAndDoesNotTimeoutSameIdentifier() {
Object identifier = new Object(); Object identifier = new Object();
Runnable mock1 = mock(Runnable.class); Runnable mock1 = mock(Runnable.class);
doAnswer(a -> sleep(BLOCK)).when(mock1).run(); doAnswer(a -> sleep(BLOCK)).when(mock1).run();
@ -470,43 +426,34 @@ public class SafeCallerImplTest extends JavaTest {
} }
@Test @Test
public void testAsyncSequentialSameIdentifier() throws Exception { public void testAsyncSequentialSameIdentifier() {
Runnable mock = mock(Runnable.class); Runnable mock = mock(Runnable.class);
doAnswer(a -> sleep(BLOCK)).when(mock).run(); doAnswer(a -> sleep(BLOCK)).when(mock).run();
for (int i = 0; i < THREAD_POOL_SIZE; i++) { for (int i = 0; i < THREAD_POOL_SIZE; i++) {
assertDurationBelow(GRACE, () -> { assertDurationBelow(GRACE,
safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT).withAsync().build().run(); () -> safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT).withAsync().build().run());
});
} }
assertDurationBetween(BLOCK * (THREAD_POOL_SIZE - 1) - GRACE, (BLOCK + GRACE) * (THREAD_POOL_SIZE), () -> { assertDurationBetween(BLOCK * (THREAD_POOL_SIZE - 1) - GRACE, (BLOCK + GRACE) * (THREAD_POOL_SIZE),
waitForAssert(() -> { () -> waitForAssert(() -> verify(mock, times(THREAD_POOL_SIZE)).run()));
verify(mock, times(THREAD_POOL_SIZE)).run();
});
});
} }
@Test @Test
public void testAsyncExceedingThreadPoolDifferentIdentifier() throws Exception { public void testAsyncExceedingThreadPoolDifferentIdentifier() {
Runnable mock = mock(Runnable.class); Runnable mock = mock(Runnable.class);
doAnswer(a -> sleep(BLOCK)).when(mock).run(); doAnswer(a -> sleep(BLOCK)).when(mock).run();
for (int i = 0; i < THREAD_POOL_SIZE * 2; i++) { for (int i = 0; i < THREAD_POOL_SIZE * 2; i++) {
assertDurationBelow(GRACE, () -> { assertDurationBelow(GRACE, () -> safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT)
safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT).withIdentifier(new Object()).withAsync() .withIdentifier(new Object()).withAsync().build().run());
.build().run();
});
} }
assertDurationBetween(BLOCK - GRACE, BLOCK + TIMEOUT + THREAD_POOL_SIZE * 2 * GRACE, () -> { assertDurationBetween(BLOCK - GRACE, BLOCK + TIMEOUT + THREAD_POOL_SIZE * 2 * GRACE,
waitForAssert(() -> { () -> waitForAssert(() -> verify(mock, times(THREAD_POOL_SIZE * 2)).run()));
verify(mock, times(THREAD_POOL_SIZE * 2)).run();
});
});
} }
@Test @Test
public void testAsyncExecutionOrder() throws Exception { public void testAsyncExecutionOrder() {
Queue<Integer> q = new ConcurrentLinkedQueue<>(); Queue<Integer> q = new ConcurrentLinkedQueue<>();
final Random r = new Random(); final Random r = new Random();
@ -518,9 +465,7 @@ public class SafeCallerImplTest extends JavaTest {
}, Runnable.class).withTimeout(TIMEOUT).withAsync().withIdentifier(q).build().run(); }, Runnable.class).withTimeout(TIMEOUT).withAsync().withIdentifier(q).build().run();
} }
waitForAssert(() -> { waitForAssert(() -> assertThat(q.size(), is(THREAD_POOL_SIZE * 10)));
assertThat(q.size(), is(THREAD_POOL_SIZE * 10));
});
int expected = 0; int expected = 0;
for (int actual : q) { for (int actual : q) {
@ -599,8 +544,9 @@ public class SafeCallerImplTest extends JavaTest {
} }
private void configureSingleThread() { private void configureSingleThread() {
safeCaller.modified(new HashMap<String, Object>() { safeCaller.modified(new HashMap<>() {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
{ {
put("singleThread", "true"); put("singleThread", "true");
} }
@ -612,7 +558,7 @@ public class SafeCallerImplTest extends JavaTest {
* <p> * <p>
* Returns immediately. * Returns immediately.
* *
* @param runnable * @param runnable The runnable to execute
*/ */
private void spawn(Runnable runnable) { private void spawn(Runnable runnable) {
AssertingThread t = new AssertingThread(runnable); AssertingThread t = new AssertingThread(runnable);
@ -625,7 +571,7 @@ public class SafeCallerImplTest extends JavaTest {
* <p> * <p>
* This is required in order to catch exceptions and especially {@link AssertionError}s which happened inside. * This is required in order to catch exceptions and especially {@link AssertionError}s which happened inside.
* *
* @throws InterruptedException * @throws InterruptedException if interrupted
*/ */
private void joinAll() throws InterruptedException { private void joinAll() throws InterruptedException {
while (!threads.isEmpty()) { while (!threads.isEmpty()) {