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
parent
0e7e7a37b7
commit
ee7095d96d
|
@ -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()) {
|
||||||
|
|
Loading…
Reference in New Issue