Fix more SAT findings and add a few suppressions (#2335)

* Fix more SAT findings and add a few suppressions

Signed-off-by: Wouter Born <github@maindrain.net>
This commit is contained in:
Wouter Born 2021-05-05 20:59:59 +02:00 committed by GitHub
parent 99a5f571c7
commit 7579aa4d31
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 111 additions and 91 deletions

View File

@ -298,6 +298,7 @@ public class ScriptFileWatcher extends AbstractWatchService
} }
@Override @Override
@SuppressWarnings("PMD.EmptyWhileStmt")
public synchronized void onReadyMarkerRemoved(ReadyMarker readyMarker) { public synchronized void onReadyMarkerRemoved(ReadyMarker readyMarker) {
int newLevel = Integer.parseInt(readyMarker.getIdentifier()); int newLevel = Integer.parseInt(readyMarker.getIdentifier());

View File

@ -12,8 +12,7 @@
*/ */
package org.openhab.core.automation.module.script.rulesupport.internal.loader; package org.openhab.core.automation.module.script.rulesupport.internal.loader;
import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; import static java.nio.file.StandardWatchEventKinds.*;
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.ArgumentMatchers.*; import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@ -26,6 +25,7 @@ import java.util.concurrent.ScheduledExecutorService;
import javax.script.ScriptEngine; import javax.script.ScriptEngine;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -45,15 +45,15 @@ import org.opentest4j.AssertionFailedError;
* *
* @author Jonathan Gilbert - initial contribution * @author Jonathan Gilbert - initial contribution
*/ */
@NonNullByDefault
class ScriptFileWatcherTest { class ScriptFileWatcherTest {
private ScriptFileWatcher scriptFileWatcher; private @NonNullByDefault({}) ScriptFileWatcher scriptFileWatcher;
private ScriptEngineManager scriptEngineManager; private @NonNullByDefault({}) ScriptEngineManager scriptEngineManager;
private DependencyTracker dependencyTracker; private @NonNullByDefault({}) DependencyTracker dependencyTracker;
private ReadyService readyService; private @NonNullByDefault({}) ReadyService readyService;
@TempDir protected @NonNullByDefault({}) @TempDir Path tempScriptDir;
Path tempScriptDir;
@BeforeEach @BeforeEach
public void setUp() { public void setUp() {
@ -324,8 +324,11 @@ class ScriptFileWatcherTest {
verify(dependencyTracker).addLibForScript(p.toFile().toURI().toString(), "test"); verify(dependencyTracker).addLibForScript(p.toFile().toURI().toString(), "test");
} }
/**
* @see https://github.com/openhab/openhab-core/issues/2246
*/
@Test @Test
public void testRemoveBeforeReAdd_bug2246() { public void testRemoveBeforeReAdd() {
when(scriptEngineManager.isSupported("js")).thenReturn(true); when(scriptEngineManager.isSupported("js")).thenReturn(true);
ScriptEngineContainer scriptEngineContainer = mock(ScriptEngineContainer.class); ScriptEngineContainer scriptEngineContainer = mock(ScriptEngineContainer.class);
when(scriptEngineContainer.getScriptEngine()).thenReturn(mock(ScriptEngine.class)); when(scriptEngineContainer.getScriptEngine()).thenReturn(mock(ScriptEngine.class));

View File

@ -125,8 +125,10 @@ public class AutomationResourceBundlesEventQueue<@NonNull E> implements Runnable
return; return;
} }
} }
} catch (IllegalStateException e) {
continue;
} catch (Throwable t) { } catch (Throwable t) {
if (!closed && !(t instanceof IllegalStateException)) { if (!closed) {
logger.warn("Processing bundle event {}, for automation resource bundle '{}' failed", logger.warn("Processing bundle event {}, for automation resource bundle '{}' failed",
event.getType(), event.getBundle().getSymbolicName(), t); event.getType(), event.getBundle().getSymbolicName(), t);
} }

View File

@ -91,7 +91,7 @@ public class AuthFilter implements ContainerRequestFilter {
private ExpiringUserSecurityContextCache authCache = new ExpiringUserSecurityContextCache( private ExpiringUserSecurityContextCache authCache = new ExpiringUserSecurityContextCache(
Duration.ofHours(cacheExpiration).toMillis()); Duration.ofHours(cacheExpiration).toMillis());
private final byte[] RANDOM_BYTES = new byte[32]; private static final byte[] RANDOM_BYTES = new byte[32];
private final JwtHelper jwtHelper; private final JwtHelper jwtHelper;
private final UserRegistry userRegistry; private final UserRegistry userRegistry;

View File

@ -57,7 +57,7 @@ public class PlainMessageBodyReader<T> implements MessageBodyReader<T> {
} else if (type.equals(Byte[].class) || genericType.equals(Byte[].class)) { } else if (type.equals(Byte[].class) || genericType.equals(Byte[].class)) {
final Byte[] dataB = new Byte[data.length]; final Byte[] dataB = new Byte[data.length];
for (int i = 0; i < data.length; ++i) { for (int i = 0; i < data.length; ++i) {
dataB[i] = data[i]; dataB[i] = Byte.valueOf(data[i]);
} }
return (T) dataB; return (T) dataB;
} else { } else {

View File

@ -20,7 +20,7 @@ import org.openhab.core.thing.link.dto.ItemChannelLinkDTO;
* This is an enriched data transfer object that is used to serialize items channel links with dynamic data like the * This is an enriched data transfer object that is used to serialize items channel links with dynamic data like the
* editable flag. * editable flag.
* *
* @author Christoph Weitkamp- Initial contribution * @author Christoph Weitkamp - Initial contribution
*/ */
public class EnrichedItemChannelLinkDTO extends ItemChannelLinkDTO { public class EnrichedItemChannelLinkDTO extends ItemChannelLinkDTO {

View File

@ -38,6 +38,8 @@ import org.openhab.core.io.transport.modbus.endpoint.ModbusSlaveEndpoint;
import org.openhab.core.io.transport.modbus.endpoint.ModbusTCPSlaveEndpoint; import org.openhab.core.io.transport.modbus.endpoint.ModbusTCPSlaveEndpoint;
import org.openhab.core.io.transport.modbus.internal.ModbusManagerImpl; import org.openhab.core.io.transport.modbus.internal.ModbusManagerImpl;
import org.openhab.core.test.java.JavaTest; import org.openhab.core.test.java.JavaTest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import gnu.io.SerialPort; import gnu.io.SerialPort;
import net.wimpi.modbus.Modbus; import net.wimpi.modbus.Modbus;
@ -68,6 +70,8 @@ import net.wimpi.modbus.util.SerialParameters;
@MockitoSettings(strictness = Strictness.WARN) @MockitoSettings(strictness = Strictness.WARN)
public class IntegrationTestSupport extends JavaTest { public class IntegrationTestSupport extends JavaTest {
private final Logger logger = LoggerFactory.getLogger(IntegrationTestSupport.class);
public enum ServerType { public enum ServerType {
TCP, TCP,
UDP, UDP,
@ -175,11 +179,9 @@ public class IntegrationTestSupport extends JavaTest {
if (ServerType.TCP.equals(serverType)) { if (ServerType.TCP.equals(serverType)) {
verify(tcpConnectionFactory, times(expectedConnections)).create(any(Socket.class)); verify(tcpConnectionFactory, times(expectedConnections)).create(any(Socket.class));
} else if (ServerType.UDP.equals(serverType)) { } else if (ServerType.UDP.equals(serverType)) {
// No-op logger.debug("No-op, UDP server type");
// verify(udpTerminalFactory, times(expectedConnections)).create(any(InetAddress.class),
// any(Integer.class));
} else if (ServerType.SERIAL.equals(serverType)) { } else if (ServerType.SERIAL.equals(serverType)) {
// No-op logger.debug("No-op, SERIAL server type");
} else { } else {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@ -206,14 +208,15 @@ public class IntegrationTestSupport extends JavaTest {
private void stopServer() { private void stopServer() {
if (ServerType.TCP.equals(serverType)) { if (ServerType.TCP.equals(serverType)) {
tcpListener.stop(); tcpListener.stop();
logger.debug("Stopped TCP listener, tcpModbusPort={}", tcpModbusPort);
} else if (ServerType.UDP.equals(serverType)) { } else if (ServerType.UDP.equals(serverType)) {
udpListener.stop(); udpListener.stop();
System.err.println(udpModbusPort); logger.debug("Stopped UDP listener, udpModbusPort={}", udpModbusPort);
} else if (ServerType.SERIAL.equals(serverType)) { } else if (ServerType.SERIAL.equals(serverType)) {
try { try {
serialServerThread.join(100); serialServerThread.join(100);
} catch (InterruptedException e) { } catch (InterruptedException e) {
System.err.println("Serial server thread .join() interrupted! Will interrupt it now."); logger.debug("Serial server thread .join() interrupted! Will interrupt it now.");
} }
serialServerThread.interrupt(); serialServerThread.interrupt();
} else { } else {

View File

@ -677,7 +677,6 @@ public class SmokeTest extends IntegrationTestSupport {
} catch (AssertionError e) { } catch (AssertionError e) {
unexpectedCount.incrementAndGet(); unexpectedCount.incrementAndGet();
} }
} else { } else {
unexpectedCount.incrementAndGet(); unexpectedCount.incrementAndGet();
} }
@ -885,7 +884,6 @@ public class SmokeTest extends IntegrationTestSupport {
Thread.sleep(1000); Thread.sleep(1000);
// Still one connection open even after closing second connection // Still one connection open even after closing second connection
assertThat(getNumberOfOpenClients(SOCKET_SPY), is(equalTo(1L))); assertThat(getNumberOfOpenClients(SOCKET_SPY), is(equalTo(1L)));
} // 4. close (the last) comms } // 4. close (the last) comms
// ensure that open connections are closed // ensure that open connections are closed
// (despite huge "reconnect after millis") // (despite huge "reconnect after millis")
@ -937,7 +935,6 @@ public class SmokeTest extends IntegrationTestSupport {
long openSocketsAfter = getNumberOfOpenClients(SOCKET_SPY); long openSocketsAfter = getNumberOfOpenClients(SOCKET_SPY);
assertThat(openSocketsAfter, is(equalTo(0L))); assertThat(openSocketsAfter, is(equalTo(0L)));
}, 60_000, 50); }, 60_000, 50);
} }
} }

View File

@ -83,8 +83,7 @@ public class TestPersistenceService implements QueryablePersistenceService {
for (int i = 0; i <= 15; i++) { for (int i = 0; i <= 15; i++) {
final int hours = i; final int hours = i;
final ZonedDateTime theDate = nowMinusFifteenHours.plusHours(hours); final ZonedDateTime theDate = nowMinusFifteenHours.plusHours(hours);
if (theDate.isBefore(beginDate) || theDate.isAfter(endDate)) { if (!theDate.isBefore(beginDate) && !theDate.isAfter(endDate)) {
} else {
results.add(new HistoricItem() { results.add(new HistoricItem() {
@Override @Override
public ZonedDateTime getTimestamp() { public ZonedDateTime getTimestamp() {

View File

@ -180,6 +180,7 @@ public class JavaTest {
* @param sleepTime interval for checking the condition * @param sleepTime interval for checking the condition
* @return the return value of the supplied assertion object's function on success * @return the return value of the supplied assertion object's function on success
*/ */
@SuppressWarnings("PMD.AvoidCatchingNPE")
private <T> T waitForAssert(Supplier<T> assertion, @Nullable Runnable beforeLastCall, long timeout, private <T> T waitForAssert(Supplier<T> assertion, @Nullable Runnable beforeLastCall, long timeout,
long sleepTime) { long sleepTime) {
final long timeoutNs = TimeUnit.MILLISECONDS.toNanos(timeout); final long timeoutNs = TimeUnit.MILLISECONDS.toNanos(timeout);

View File

@ -83,6 +83,7 @@ public class ChannelCommandDescriptionProvider implements CommandDescriptionProv
return null; return null;
} }
@SuppressWarnings("PMD.CompareObjectsWithEquals")
private @Nullable CommandDescription getDynamicCommandDescription(Channel channel, private @Nullable CommandDescription getDynamicCommandDescription(Channel channel,
@Nullable CommandDescription originalCommandDescription, @Nullable Locale locale) { @Nullable CommandDescription originalCommandDescription, @Nullable Locale locale) {
for (DynamicCommandDescriptionProvider dynamicCommandDescriptionProvider : dynamicCommandDescriptionProviders) { for (DynamicCommandDescriptionProvider dynamicCommandDescriptionProvider : dynamicCommandDescriptionProviders) {
@ -90,6 +91,7 @@ public class ChannelCommandDescriptionProvider implements CommandDescriptionProv
CommandDescription dynamicCommandDescription = dynamicCommandDescriptionProvider CommandDescription dynamicCommandDescription = dynamicCommandDescriptionProvider
.getCommandDescription(channel, originalCommandDescription, locale); .getCommandDescription(channel, originalCommandDescription, locale);
if (dynamicCommandDescription != null) { if (dynamicCommandDescription != null) {
// Compare by reference to make sure a new command description is returned
if (dynamicCommandDescription == originalCommandDescription) { if (dynamicCommandDescription == originalCommandDescription) {
logger.error( logger.error(
"Dynamic command description matches original command description. DynamicCommandDescriptionProvider implementations must never return the original command description. {} has to be fixed.", "Dynamic command description matches original command description. DynamicCommandDescriptionProvider implementations must never return the original command description. {} has to be fixed.",

View File

@ -128,12 +128,14 @@ public class ChannelStateDescriptionProvider implements StateDescriptionFragment
return null; return null;
} }
@SuppressWarnings("PMD.CompareObjectsWithEquals")
private @Nullable StateDescription getDynamicStateDescription(Channel channel, private @Nullable StateDescription getDynamicStateDescription(Channel channel,
@Nullable StateDescription originalStateDescription, @Nullable Locale locale) { @Nullable StateDescription originalStateDescription, @Nullable Locale locale) {
for (DynamicStateDescriptionProvider provider : dynamicStateDescriptionProviders) { for (DynamicStateDescriptionProvider provider : dynamicStateDescriptionProviders) {
StateDescription dynamicStateDescription = provider.getStateDescription(channel, originalStateDescription, StateDescription dynamicStateDescription = provider.getStateDescription(channel, originalStateDescription,
locale); locale);
if (dynamicStateDescription != null) { if (dynamicStateDescription != null) {
// Compare by reference to make sure a new state description is returned
if (dynamicStateDescription == originalStateDescription) { if (dynamicStateDescription == originalStateDescription) {
logger.error( logger.error(
"Dynamic state description matches original state description. DynamicStateDescriptionProvider implementations must never return the original state description. {} has to be fixed.", "Dynamic state description matches original state description. DynamicStateDescriptionProvider implementations must never return the original state description. {} has to be fixed.",

View File

@ -604,6 +604,7 @@ public class ThingManagerImpl
} }
} }
@SuppressWarnings("PMD.CompareObjectsWithEquals")
private @Nullable ThingHandler replaceThing(@Nullable Thing oldThing, Thing newThing) { private @Nullable ThingHandler replaceThing(@Nullable Thing oldThing, Thing newThing) {
final ThingHandler thingHandler = thingHandlers.get(newThing.getUID()); final ThingHandler thingHandler = thingHandlers.get(newThing.getUID());
if (oldThing != newThing) { if (oldThing != newThing) {

View File

@ -126,7 +126,7 @@ public class IconServlet extends OpenHABServlet {
if (provider == null) { if (provider == null) {
provider = provider2; provider = provider2;
format = otherFormat; format = otherFormat;
} else if (provider2 != provider) { } else if (!provider2.equals(provider)) {
Integer prio = provider.hasIcon(category, iconSetId, format); Integer prio = provider.hasIcon(category, iconSetId, format);
Integer prio2 = provider2.hasIcon(category, iconSetId, otherFormat); Integer prio2 = provider2.hasIcon(category, iconSetId, otherFormat);
if ((prio != null && prio2 != null && prio < prio2) || (prio == null && prio2 != null)) { if ((prio != null && prio2 != null && prio < prio2) || (prio == null && prio2 != null)) {

View File

@ -100,14 +100,13 @@ public class BlockingProxyServlet extends HttpServlet {
HttpField header = iterator.next(); HttpField header = iterator.next();
response.setHeader(header.getName(), header.getValue()); response.setHeader(header.getName(), header.getValue());
} }
} catch (TimeoutException e) {
logger.warn("Proxy servlet failed to stream content due to a timeout");
response.sendError(HttpServletResponse.SC_GATEWAY_TIMEOUT);
return;
} catch (Exception e) { } catch (Exception e) {
if (e instanceof TimeoutException) { logger.warn("Proxy servlet failed to stream content: {}", e.getMessage());
logger.warn("Proxy servlet failed to stream content due to a timeout"); response.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
response.sendError(HttpServletResponse.SC_GATEWAY_TIMEOUT);
} else {
logger.warn("Proxy servlet failed to stream content: {}", e.getMessage());
response.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
}
return; return;
} }
// now copy/stream the body content // now copy/stream the body content

View File

@ -61,7 +61,7 @@ public class ThreadedEventHandler implements Closeable {
logger.trace("inspect event: {}", event); logger.trace("inspect event: {}", event);
if (event == null) { if (event == null) {
logger.debug("Hey, you have really very few events."); logger.debug("Hey, you have really very few events.");
} else if (event == notifyEvent) { } else if (event.equals(notifyEvent)) {
// received an internal notification // received an internal notification
} else { } else {
worker.handleEvent(event); worker.handleEvent(event);

View File

@ -20,6 +20,7 @@ import static org.mockito.Mockito.*;
import javax.measure.quantity.Length; import javax.measure.quantity.Length;
import javax.measure.quantity.Temperature; import javax.measure.quantity.Temperature;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.openhab.core.i18n.UnitProvider; import org.openhab.core.i18n.UnitProvider;
@ -38,9 +39,10 @@ import org.openhab.core.types.UnDefType;
* *
* @author Henning Treu - Initial contribution * @author Henning Treu - Initial contribution
*/ */
@NonNullByDefault
public class ItemStateConverterImplTest { public class ItemStateConverterImplTest {
private ItemStateConverterImpl itemStateConverter; private @NonNullByDefault({}) ItemStateConverterImpl itemStateConverter;
@BeforeEach @BeforeEach
public void setup() { public void setup() {
@ -57,6 +59,7 @@ public class ItemStateConverterImplTest {
} }
@Test @Test
@SuppressWarnings("PMD.CompareObjectsWithEquals")
public void testNoConversion() { public void testNoConversion() {
Item item = new NumberItem("number"); Item item = new NumberItem("number");
State originalState = new DecimalType(12.34); State originalState = new DecimalType(12.34);

View File

@ -565,7 +565,6 @@ public class AutomationIntegrationTest extends JavaOSGiTest {
@Test @Test
public void testChainOfCompositeModules() throws ItemNotFoundException { public void testChainOfCompositeModules() throws ItemNotFoundException {
Configuration triggerConfig = new Configuration(Map.of("itemName", "myMotionItem4")); Configuration triggerConfig = new Configuration(Map.of("itemName", "myMotionItem4"));
Map<String, Object> eventInputs = Map.of("event", "ItemStateChangeTrigger4.event");
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.put("itemName", "myLampItem4"); params.put("itemName", "myLampItem4");
params.put("command", "ON"); params.put("command", "ON");
@ -818,7 +817,7 @@ public class AutomationIntegrationTest extends JavaOSGiTest {
RuleTemplateProvider templateProvider = new RuleTemplateProvider() { RuleTemplateProvider templateProvider = new RuleTemplateProvider() {
@Override @Override
public @Nullable RuleTemplate getTemplate(String UID, @Nullable Locale locale) { public @Nullable RuleTemplate getTemplate(String UID, @Nullable Locale locale) {
if (UID == templateUID) { if (UID.equals(templateUID)) {
return template; return template;
} else { } else {
return null; return null;
@ -860,9 +859,9 @@ public class AutomationIntegrationTest extends JavaOSGiTest {
@Override @Override
public <T extends ModuleType> @Nullable T getModuleType(String UID, @Nullable Locale locale) { public <T extends ModuleType> @Nullable T getModuleType(String UID, @Nullable Locale locale) {
if (UID == triggerTypeUID) { if (UID.equals(triggerTypeUID)) {
return (T) triggerType; return (T) triggerType;
} else if (UID == actionTypeUID) { } else if (UID.equals(actionTypeUID)) {
return (T) actionType; return (T) actionType;
} else { } else {
return null; return null;

View File

@ -23,6 +23,8 @@ import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo; import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean; import java.lang.management.ThreadMXBean;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.time.Duration;
import java.time.Instant;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -31,11 +33,12 @@ import java.util.Random;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -53,6 +56,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)
@NonNullByDefault
public class SafeCallerImplTest extends JavaTest { public class SafeCallerImplTest extends JavaTest {
private static final int THREAD_POOL_SIZE = 3; private static final int THREAD_POOL_SIZE = 3;
@ -68,13 +72,14 @@ public class SafeCallerImplTest extends JavaTest {
private final Logger logger = LoggerFactory.getLogger(SafeCallerImplTest.class); private final Logger logger = LoggerFactory.getLogger(SafeCallerImplTest.class);
private SafeCallerImpl safeCaller;
private QueueingThreadPoolExecutor scheduler;
private TestInfo testInfo;
private final List<AssertingThread> threads = new LinkedList<>(); private final List<AssertingThread> threads = new LinkedList<>();
private @Mock Runnable mockTimeoutHandler; private @NonNullByDefault({}) SafeCallerImpl safeCaller;
private @Mock Consumer<Throwable> mockErrorHandler; private @NonNullByDefault({}) QueueingThreadPoolExecutor scheduler;
private @NonNullByDefault({}) TestInfo testInfo;
private @NonNullByDefault({}) @Mock Runnable timeoutHandlerMock;
private @NonNullByDefault({}) @Mock Consumer<Throwable> errorHandlerMock;
public static interface ITarget { public static interface ITarget {
public String method(); public String method();
@ -135,9 +140,9 @@ public class SafeCallerImplTest extends JavaTest {
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(mockErrorHandler).build().run(); safeCaller.create(mock, Runnable.class).onException(errorHandlerMock).build().run();
waitForAssert(() -> { waitForAssert(() -> {
verify(mockErrorHandler).accept(isA(Throwable.class)); verify(errorHandlerMock).accept(isA(Throwable.class));
}); });
} }
@ -146,9 +151,9 @@ 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();
safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT).onTimeout(mockTimeoutHandler).build().run(); safeCaller.create(mock, Runnable.class).withTimeout(TIMEOUT).onTimeout(timeoutHandlerMock).build().run();
waitForAssert(() -> { waitForAssert(() -> {
verify(mockTimeoutHandler).run(); verify(timeoutHandlerMock).run();
}); });
} }
@ -294,10 +299,10 @@ public class SafeCallerImplTest extends JavaTest {
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).onTimeout(mockTimeoutHandler).build() safeCaller.create(mock, Runnable.class).withTimeout(BLOCK + GRACE * 2).onTimeout(timeoutHandlerMock).build()
.run(); .run();
}); });
verifyNoMoreInteractions(mockTimeoutHandler); verifyNoMoreInteractions(timeoutHandlerMock);
} }
@Test @Test
@ -388,11 +393,11 @@ public class SafeCallerImplTest extends JavaTest {
assertDurationBelow(GRACE, () -> { assertDurationBelow(GRACE, () -> {
safeCaller.create(mock1, Runnable.class).withTimeout(TIMEOUT).withAsync().withIdentifier(identifier) safeCaller.create(mock1, Runnable.class).withTimeout(TIMEOUT).withAsync().withIdentifier(identifier)
.onTimeout(mockTimeoutHandler).onException(mockErrorHandler).build().run(); .onTimeout(timeoutHandlerMock).onException(errorHandlerMock).build().run();
}); });
waitForAssert(() -> verify(mock1, times(1)).run()); waitForAssert(() -> verify(mock1, times(1)).run());
waitForAssert(() -> verify(mockTimeoutHandler, times(1)).run()); waitForAssert(() -> verify(timeoutHandlerMock, times(1)).run());
verifyNoMoreInteractions(mockErrorHandler); verifyNoMoreInteractions(errorHandlerMock);
} }
@Test @Test
@ -403,12 +408,12 @@ public class SafeCallerImplTest extends JavaTest {
assertDurationBelow(GRACE, () -> { assertDurationBelow(GRACE, () -> {
safeCaller.create(mock1, Runnable.class).withTimeout(TIMEOUT).withAsync().withIdentifier(identifier) safeCaller.create(mock1, Runnable.class).withTimeout(TIMEOUT).withAsync().withIdentifier(identifier)
.onTimeout(mockTimeoutHandler).onException(mockErrorHandler).build().run(); .onTimeout(timeoutHandlerMock).onException(errorHandlerMock).build().run();
}); });
waitForAssert(() -> verify(mock1, times(1)).run()); waitForAssert(() -> verify(mock1, times(1)).run());
waitForAssert(() -> verify(mockErrorHandler, times(1)).accept(isA(Exception.class))); waitForAssert(() -> verify(errorHandlerMock, times(1)).accept(isA(Exception.class)));
verifyNoMoreInteractions(mockErrorHandler); verifyNoMoreInteractions(errorHandlerMock);
verifyNoMoreInteractions(mockTimeoutHandler); verifyNoMoreInteractions(timeoutHandlerMock);
} }
@Test @Test
@ -538,24 +543,28 @@ public class SafeCallerImplTest extends JavaTest {
} }
private void assertDurationBetween(long low, long high, Runnable runnable) { private void assertDurationBetween(long low, long high, Runnable runnable) {
long startNanos = System.nanoTime(); Instant start = Instant.now();
try { try {
runnable.run(); runnable.run();
} finally { } finally {
long durationMillis = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNanos); Duration duration = Duration.between(start, Instant.now());
try { assertDurationBetween(low, high, duration.toMillis());
if (low > -1) { }
assertTrue(durationMillis >= low, MessageFormat }
.format("Duration should have been above {0} but was {1}", low, durationMillis));
} private void assertDurationBetween(long low, long high, long durationMillis) throws AssertionError {
if (high > -1) { try {
assertTrue(durationMillis < high, MessageFormat if (low > -1) {
.format("Duration should have been below {0} but was {1}", high, durationMillis)); assertTrue(durationMillis >= low,
} MessageFormat.format("Duration should have been above {0} but was {1}", low, durationMillis));
} catch (AssertionError e) {
logger.debug("{}", createThreadDump(testInfo.getTestMethod().get().getName()));
throw e;
} }
if (high > -1) {
assertTrue(durationMillis < high,
MessageFormat.format("Duration should have been below {0} but was {1}", high, durationMillis));
}
} catch (AssertionError e) {
logger.debug("{}", createThreadDump(testInfo.getTestMethod().get().getName()));
throw e;
} }
} }
@ -580,7 +589,7 @@ public class SafeCallerImplTest extends JavaTest {
return sb.toString(); return sb.toString();
} }
private static Object sleep(int duration) { private static @Nullable Object sleep(int duration) {
try { try {
Thread.sleep(duration); Thread.sleep(duration);
} catch (InterruptedException e) { } catch (InterruptedException e) {
@ -632,8 +641,8 @@ public class SafeCallerImplTest extends JavaTest {
} }
private static class AssertingThread extends Thread { private static class AssertingThread extends Thread {
private AssertionError assertionError; private @Nullable AssertionError assertionError;
private RuntimeException runtimeException; private @Nullable RuntimeException runtimeException;
public AssertingThread(Runnable runnable) { public AssertingThread(Runnable runnable) {
super(runnable); super(runnable);

View File

@ -1,27 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suppressions PUBLIC <!DOCTYPE suppressions PUBLIC "-//Puppy Crawl//DTD Suppressions 1.1//EN" "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
"-//Puppy Crawl//DTD Suppressions 1.1//EN"
"http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
<suppressions> <suppressions>
<!-- These suppressions define which files to be suppressed for which checks. --> <!-- These suppressions define which files to be suppressed for which checks. -->
<suppress files=".+[\\/]internal[\\/].+\.java" checks="JavadocType|JavadocVariable|JavadocMethod|MissingJavadocFilterCheck"/> <suppress files=".+[\\/]internal[\\/].+\.java" checks="JavadocType|JavadocVariable|JavadocMethod|MissingJavadocFilterCheck"/>
<suppress files=".+DTO\.java" checks="JavadocType|JavadocVariable|JavadocMethod|MissingJavadocFilterCheck" /> <suppress files=".+DTO\.java" checks="JavadocType|JavadocVariable|JavadocMethod|MissingJavadocFilterCheck|NullAnnotationsCheck" />
<suppress files=".+Impl\.java" checks="JavadocType|JavadocVariable|JavadocMethod|MissingJavadocFilterCheck"/> <suppress files=".+Impl\.java" checks="JavadocType|JavadocVariable|JavadocMethod|MissingJavadocFilterCheck"/>
<suppress files=".+[\\/]pom\.xml" checks="OnlyTabIndentationCheck"/> <suppress files=".+[\\/]pom\.xml" checks="OnlyTabIndentationCheck"/>
<suppress files=".+[\\/]OH-INF[\\/].+\.xml" checks="OhInfXmlLabelCheck"/> <suppress files=".+[\\/]OH-INF[\\/].+\.xml" checks="OhInfXmlLabelCheck"/>
<!-- All generated files will skip the author tag check --> <!-- All generated files will skip the author tag check -->
<suppress files=".+[\\/]gen[\\/].+\.java" checks="AuthorTagCheck"/> <suppress files=".+[\\/]gen[\\/].+\.java" checks="AuthorTagCheck"/>
<!-- Some checks will be supressed for test bundles --> <!-- Some checks will be supressed for test bundles -->
<suppress files=".+.test[\\/].+" checks="RequireBundleCheck|OutsideOfLibExternalLibrariesCheck|ManifestExternalLibrariesCheck|BuildPropertiesExternalLibrariesCheck"/> <suppress files=".+.test[\\/].+" checks="RequireBundleCheck|OutsideOfLibExternalLibrariesCheck|ManifestExternalLibrariesCheck|BuildPropertiesExternalLibrariesCheck"/>
<!-- openHAB Core specific suppressions--> <!-- openHAB Core specific suppressions-->
<!-- These bundles are generated trough XText --> <!-- These bundles are generated trough XText -->
<suppress files=".+org.openhab.core.model.+" checks="RequireBundleCheck|ExportInternalPackageCheck|ManifestPackageVersionCheck|ImportExportedPackagesCheck|PackageExportsNameCheck|PomXmlCheck"/> <suppress files=".+org.openhab.core.model.+" checks="RequireBundleCheck|ExportInternalPackageCheck|ManifestPackageVersionCheck|ImportExportedPackagesCheck|PackageExportsNameCheck|PomXmlCheck"/>
<suppress files=".+org.openhab.core.config.discovery.mdns.internal.MDNSDiscoveryService.java|.+org.openhab.core.config.discovery.upnp.internal.UpnpDiscoveryService.java|.+org.openhab.core.io.console.eclipse.internal.ConsoleSupportEclipse.java|.+org.openhab.core.io.console.rfc147.internal.CommandWrapper.java|.+org.openhab.core.library.unit.MetricPrefix.java" checks="MethodNameCheck"/> <suppress files=".+org.openhab.core.config.core.ConfigurableService" checks="ConstantNameCheck"/>
<suppress files=".+org.openhab.core.config.discovery.mdns.internal.MDNSDiscoveryService.java|.+org.openhab.core.config.discovery.upnp.internal.UpnpDiscoveryService.java|.+org.openhab.core.io.console.eclipse.internal.ConsoleSupportEclipse.java|.+org.openhab.core.io.console.rfc147.internal.CommandWrapper.java|.+org.openhab.core.library.unit.BinaryPrefix.java|.+org.openhab.core.library.unit.MetricPrefix.java" checks="MethodNameCheck"/>
<!-- Add suppression as discussed in https://github.com/openhab/static-code-analysis/issues/265 --> <!-- Add suppression as discussed in https://github.com/openhab/static-code-analysis/issues/265 -->
<suppress files=".+org.openhab.core.common.registry.AbstractRegistry.java" checks="DeclarativeServicesDependencyInjectionCheck"/> <suppress files=".+org.openhab.core.common.registry.AbstractRegistry.java" checks="DeclarativeServicesDependencyInjectionCheck"/>