diff --git a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/ConfigStore.java b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/ConfigStore.java index 457727892f4d8..6d2a83b802d08 100644 --- a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/ConfigStore.java +++ b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/ConfigStore.java @@ -191,8 +191,9 @@ public void modified(Map properties) { InetAddress configuredAddress = null; int networkPrefixLength = 24; // Default for most networks: 255.255.255.0 - if (config.discoveryIp != null) { - discoveryIps = Collections.unmodifiableSet(Stream.of(config.discoveryIp.split(",")).map(String::trim) + String discoveryIp = config.discoveryIp; + if (discoveryIp != null) { + discoveryIps = Collections.unmodifiableSet(Stream.of(discoveryIp.split(",")).map(String::trim) .map(this::byName).filter(e -> e != null).collect(Collectors.toSet())); } else { discoveryIps = new LinkedHashSet<>(); diff --git a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/DeviceType.java b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/DeviceType.java index 0b1b0b6eb4e89..4234c10bca67e 100644 --- a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/DeviceType.java +++ b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/DeviceType.java @@ -12,6 +12,8 @@ */ package org.openhab.io.hueemulation.internal; +import org.eclipse.jdt.annotation.NonNullByDefault; + /** * The pure item type is not enough to decide how we expose an item. * We need to consider the assigned tags and category as well. This @@ -19,6 +21,7 @@ * * @author David Graeff - Initial contribution */ +@NonNullByDefault public enum DeviceType { SwitchType, WhiteType, diff --git a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/HueEmulationService.java b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/HueEmulationService.java index 1d84068b92108..51a923ee49408 100644 --- a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/HueEmulationService.java +++ b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/HueEmulationService.java @@ -47,7 +47,6 @@ import org.osgi.service.component.annotations.ReferenceCardinality; import org.osgi.service.component.annotations.ReferencePolicyOption; import org.osgi.service.event.Event; -import org.osgi.service.event.EventAdmin; import org.osgi.service.event.EventConstants; import org.osgi.service.event.EventHandler; import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants; @@ -194,7 +193,7 @@ protected void deactivate() { /** * We have a hard dependency on the {@link ConfigStore} and that it has initialized the Hue DataStore config * completely. That initialization happens asynchronously and therefore we cannot rely on OSGi activate/modified - * state changes. Instead the {@link EventAdmin} is used and we listen for the + * state changes. Instead the {@link org.osgi.service.event.EventAdmin} is used and we listen for the * {@link ConfigStore#EVENT_ADDRESS_CHANGED} event that is fired as soon as the config is ready. */ @Override diff --git a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/RuleUtils.java b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/RuleUtils.java index 8be63e645954f..15d28b5f6f98c 100644 --- a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/RuleUtils.java +++ b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/RuleUtils.java @@ -86,7 +86,6 @@ public static String[] computeRandomizedDayTime(String baseTime, @Nullable Strin * {@code "/api//lights/1/state"} * @throws IllegalStateException Thrown if address is invalid */ - @SuppressWarnings({ "unused", "null" }) public static void validateHueHttpAddress(HueDataStore ds, String address) throws IllegalStateException { String[] validation = address.split("/"); if (validation.length < 6 || !validation[0].isEmpty() || !"api".equals(validation[1])) { @@ -113,7 +112,6 @@ public static class ConfigHttpAction { public String body = ""; } - @SuppressWarnings({ "unused", "null" }) public static @Nullable HueCommand httpActionToHueCommand(HueDataStore ds, Action a, @Nullable String ruleName) { ConfigHttpAction config = a.getConfiguration().as(ConfigHttpAction.class); diff --git a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/StateUtils.java b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/StateUtils.java index f9184c1f2933b..cf1840af6b96e 100644 --- a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/StateUtils.java +++ b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/StateUtils.java @@ -430,30 +430,29 @@ public static AbstractHueState adjustedColorStateFromItemState(State itemState, if (lastCommand != null && lastHueChange != null) { if (lastCommand instanceof HSBType) { - if (hueState instanceof HueStateColorBulb && itemState.as(HSBType.class).equals(lastCommand)) { - HueStateColorBulb c = (HueStateColorBulb) hueState; - + if (hueState instanceof HueStateColorBulb hueStateColorBulb + && lastCommand.equals(itemState.as(HSBType.class))) { if (lastHueChange.bri != null) { - c.bri = lastHueChange.bri; + hueStateColorBulb.bri = lastHueChange.bri; } if (lastHueChange.hue != null) { - c.hue = lastHueChange.hue; + hueStateColorBulb.hue = lastHueChange.hue; } if (lastHueChange.sat != null) { - c.sat = lastHueChange.sat; + hueStateColorBulb.sat = lastHueChange.sat; } // Although we can't set a colour temperature in OH // this keeps Alexa happy when asking to turn a light // to white. if (lastHueChange.ct != null) { - c.ct = lastHueChange.ct; + hueStateColorBulb.ct = lastHueChange.ct; } } } else if (lastCommand instanceof PercentType) { - if (hueState instanceof HueStateBulb && itemState != null + if (hueState instanceof HueStateBulb hueStateBulb && lastCommand.equals(itemState.as(PercentType.class))) { if (lastHueChange.bri != null) { - ((HueStateBulb) hueState).bri = lastHueChange.bri; + hueStateBulb.bri = lastHueChange.bri; } } } diff --git a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/automation/AbsoluteDateTimeTriggerHandler.java b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/automation/AbsoluteDateTimeTriggerHandler.java index f5e8f3083b664..fc5014c135e14 100644 --- a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/automation/AbsoluteDateTimeTriggerHandler.java +++ b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/automation/AbsoluteDateTimeTriggerHandler.java @@ -21,6 +21,8 @@ import java.time.temporal.TemporalAccessor; import java.util.Map; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; import org.openhab.core.automation.ModuleHandlerCallback; import org.openhab.core.automation.Trigger; import org.openhab.core.automation.handler.BaseTriggerModuleHandler; @@ -40,6 +42,7 @@ * * @author David Graeff - Initial contribution */ +@NonNullByDefault public class AbsoluteDateTimeTriggerHandler extends BaseTriggerModuleHandler implements SchedulerRunnable { private final Logger logger = LoggerFactory.getLogger(AbsoluteDateTimeTriggerHandler.class); @@ -52,13 +55,14 @@ public class AbsoluteDateTimeTriggerHandler extends BaseTriggerModuleHandler imp public static final String CFG_TIME = "time"; public static final String CFG_TIME_RND = "randomizeTime"; - private final Scheduler scheduler; - private final Instant dateTime; - private ScheduledCompletableFuture schedule; private static final String DATE_FORMAT = "yyyy-MM-dd"; private static final String TIME_FORMAT = "HH:mm:ss"; private static final String DATETIME_FORMAT = DATE_FORMAT + " " + TIME_FORMAT; + + private final Scheduler scheduler; + private final Instant dateTime; private final DateTimeFormatter dateTimeformatter; + private @Nullable ScheduledCompletableFuture schedule; public AbsoluteDateTimeTriggerHandler(Trigger module, Scheduler scheduler) { super(module); @@ -99,15 +103,19 @@ private void scheduleJob() { @Override public synchronized void dispose() { super.dispose(); + ScheduledCompletableFuture schedule = this.schedule; if (schedule != null) { schedule.cancel(true); - logger.debug("cancelled job for trigger '{}'.", module.getId()); + this.schedule = null; + logger.debug("Cancelled job for trigger '{}'.", module.getId()); } } @Override public void run() { - ((TriggerHandlerCallback) callback).triggered(module, Map.of()); + if (callback instanceof TriggerHandlerCallback triggerHandlerCallback) { + triggerHandlerCallback.triggered(module, Map.of()); + } schedule = null; } } diff --git a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/automation/HttpActionHandler.java b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/automation/HttpActionHandler.java index 4a2d337f750fa..8450ec80ccd19 100644 --- a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/automation/HttpActionHandler.java +++ b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/automation/HttpActionHandler.java @@ -14,6 +14,7 @@ import java.net.URI; import java.util.Map; +import java.util.Objects; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -74,7 +75,8 @@ public HttpActionHandler(final Action module, HttpClientFactory httpFactory) { // convert relative path to absolute one String url = config.url; if (url.startsWith("/")) { - config.url = "http://localhost:" + Integer.getInteger("org.osgi.service.http.port", 8080).toString() + url; + config.url = "http://localhost:" + + Objects.requireNonNull(Integer.getInteger("org.osgi.service.http.port", 8080)).toString() + url; } httpClient = httpFactory.createHttpClient("HttpActionHandler_" + module.getId()); diff --git a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/automation/HueRuleConditionHandler.java b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/automation/HueRuleConditionHandler.java index e84d877d02708..1e1326fb2a976 100644 --- a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/automation/HueRuleConditionHandler.java +++ b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/automation/HueRuleConditionHandler.java @@ -16,8 +16,6 @@ import java.time.LocalTime; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoField; -import java.util.ArrayList; -import java.util.List; import java.util.Map; import java.util.function.Predicate; import java.util.regex.Matcher; @@ -72,7 +70,6 @@ public class HueRuleConditionHandler extends BaseModuleHandler implem // weekdays range from Monday to Sunday (1-7). The first entry is not used private final boolean[] weekDaysAllowed = { false, false, false, false, false, false, false, false }; - @SuppressWarnings({ "null", "unused" }) public HueRuleConditionHandler(Condition module, HueDataStore ds) { super(module); config = module.getConfiguration().as(HueRuleEntry.Condition.class); @@ -106,10 +103,6 @@ public HueRuleConditionHandler(Condition module, HueDataStore ds) { throw new IllegalStateException("Can only handle groups and lights"); } - if (itemUID == null) { - throw new IllegalStateException("Can only handle groups and lights"); - } - final String value = config.value; switch (config.operator) { case eq: @@ -174,7 +167,6 @@ public HueRuleConditionHandler(Condition module, HueDataStore ds) { // Monday = 64, Tuesday = 32, Wednesday = 16, Thursday = 8, Friday = 4, Saturday = 2, Sunday = 1 int weekdaysBinaryEncoded = Integer.valueOf(m.group(1)); - List cronWeekdays = new ArrayList<>(); for (int bin = 64, c = 1; bin > 0; bin /= 2, c += 1) { if (weekdaysBinaryEncoded / bin == 1) { weekdaysBinaryEncoded = weekdaysBinaryEncoded % bin; diff --git a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/automation/RemoveRuleActionHandler.java b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/automation/RemoveRuleActionHandler.java index a91bb5456ae64..49df65143b047 100644 --- a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/automation/RemoveRuleActionHandler.java +++ b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/automation/RemoveRuleActionHandler.java @@ -40,7 +40,6 @@ public class RemoveRuleActionHandler extends BaseModuleHandler implement private RuleRegistry ruleRegistry; - @SuppressWarnings({ "null", "unused" }) public RemoveRuleActionHandler(final Action module, RuleRegistry ruleRegistry) { super(module); this.ruleRegistry = ruleRegistry; @@ -49,10 +48,11 @@ public RemoveRuleActionHandler(final Action module, RuleRegistry ruleRegistry) { throw new IllegalArgumentException("'Configuration' can not be empty."); } - ruleUID = (String) config.get(CFG_REMOVE_UID); + String ruleUID = (String) config.get(CFG_REMOVE_UID); if (ruleUID == null) { throw new IllegalArgumentException("'ruleUIDs' property must not be null."); } + this.ruleUID = ruleUID; } @Override diff --git a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/automation/TimerTriggerHandler.java b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/automation/TimerTriggerHandler.java index 15e946f99c38b..e3ce729958443 100644 --- a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/automation/TimerTriggerHandler.java +++ b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/automation/TimerTriggerHandler.java @@ -115,7 +115,9 @@ public synchronized void dispose() { @Override public Duration call() { - ((TriggerHandlerCallback) callback).triggered(module, Map.of()); + if (callback instanceof TriggerHandlerCallback triggerHandlerCallback) { + triggerHandlerCallback.triggered(module, Map.of()); + } config.repeat -= 1; if (config.repeat == 0) { schedule = null; diff --git a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/ConfigurationAccess.java b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/ConfigurationAccess.java index 48a25e3bd418e..24ba21f6c6951 100644 --- a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/ConfigurationAccess.java +++ b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/ConfigurationAccess.java @@ -109,8 +109,10 @@ public Response putFullConfigApi(@Context UriInfo uri, if (!userManagement.authorizeUser(username)) { return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized"); } - final HueChangeRequest changes; - changes = cs.gson.fromJson(body, HueChangeRequest.class); + final HueChangeRequest changes = cs.gson.fromJson(body, HueChangeRequest.class); + if (changes == null) { + return NetworkUtils.singleError(cs.gson, uri, HueResponse.INVALID_JSON, "Empty body"); + } String devicename = changes.devicename; if (devicename != null) { cs.ds.config.devicename = devicename; diff --git a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/LightsAndGroups.java b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/LightsAndGroups.java index 1806008baff89..267185067b584 100644 --- a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/LightsAndGroups.java +++ b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/LightsAndGroups.java @@ -191,8 +191,10 @@ public synchronized void added(Item newElement) { * The HUE API enforces a Group 0 that contains all lights. */ private void updateGroup0() { - cs.ds.groups.get("0").lights = cs.ds.lights.keySet().stream().map(v -> String.valueOf(v)) - .collect(Collectors.toList()); + HueGroupEntry group0 = cs.ds.groups.get("0"); + if (group0 != null) { + group0.lights = cs.ds.lights.keySet().stream().map(v -> String.valueOf(v)).toList(); + } } @Override @@ -207,7 +209,6 @@ public synchronized void removed(Item element) { /** * The tags might have changed */ - @SuppressWarnings({ "null", "unused" }) @Override public synchronized void updated(Item oldElement, Item newElement) { if (!(newElement instanceof GenericItem element)) { @@ -291,7 +292,6 @@ public Response getLightApi(@Context UriInfo uri, // return Response.ok(cs.gson.toJson(cs.ds.lights.get(id))).build(); } - @SuppressWarnings({ "null", "unused" }) @DELETE @Path("{username}/lights/{id}") @Operation(summary = "Deletes the item that is represented by this id", responses = { @@ -316,7 +316,6 @@ public Response removeLightAPI(@Context UriInfo uri, } } - @SuppressWarnings({ "null", "unused" }) @PUT @Path("{username}/lights/{id}") @Operation(summary = "Rename a light", responses = { @ApiResponse(responseCode = "200", description = "OK") }) @@ -333,6 +332,10 @@ public Response renameLightApi(@Context UriInfo uri, // final HueChangeRequest changeRequest = cs.gson.fromJson(body, HueChangeRequest.class); + if (changeRequest == null) { + return NetworkUtils.singleError(cs.gson, uri, HueResponse.INVALID_JSON, "Empty body"); + } + String name = changeRequest.name; if (name == null || name.isEmpty()) { return NetworkUtils.singleError(cs.gson, uri, HueResponse.INVALID_JSON, "Invalid request: No name set"); @@ -344,7 +347,6 @@ public Response renameLightApi(@Context UriInfo uri, // return NetworkUtils.singleSuccess(cs.gson, name, "/lights/" + id + "/name"); } - @SuppressWarnings({ "null", "unused" }) @PUT @Path("{username}/lights/{id}/state") @Operation(summary = "Set light state", responses = { @ApiResponse(responseCode = "200", description = "OK") }) @@ -390,7 +392,6 @@ public Response setLightStateApi(@Context UriInfo uri, // }.getType())).build(); } - @SuppressWarnings({ "null", "unused" }) @PUT @Path("{username}/groups/{id}/action") @Operation(summary = "Initiate group action", responses = { @@ -402,11 +403,11 @@ public Response setGroupActionApi(@Context UriInfo uri, // return NetworkUtils.singleError(cs.gson, uri, HueResponse.UNAUTHORIZED, "Not Authorized"); } HueGroupEntry hueDevice = cs.ds.groups.get(id); - GroupItem groupItem = hueDevice.groupItem; - if (hueDevice == null || groupItem == null) { + if (hueDevice == null || hueDevice.groupItem == null) { return NetworkUtils.singleError(cs.gson, uri, HueResponse.NOT_AVAILABLE, "Group not existing"); } + GroupItem groupItem = hueDevice.groupItem; HueStateChange state = cs.gson.fromJson(body, HueStateChange.class); if (state == null) { return NetworkUtils.singleError(cs.gson, uri, HueResponse.INVALID_JSON, @@ -459,7 +460,6 @@ public Response getGroupApi(@Context UriInfo uri, // return Response.ok(cs.gson.toJson(cs.ds.groups.get(id))).build(); } - @SuppressWarnings({ "null", "unused" }) @POST @Path("{username}/groups") @Operation(summary = "Create a new group", responses = { @ApiResponse(responseCode = "200", description = "OK") }) @@ -486,7 +486,6 @@ public Response postNewGroup(@Context UriInfo uri, groupItem.addTag("hueroom_" + state.roomclass); } - List groupItems = new ArrayList<>(); for (String id : state.lights) { Item item = itemRegistry.get(id); if (item == null) { @@ -502,7 +501,6 @@ public Response postNewGroup(@Context UriInfo uri, return NetworkUtils.singleSuccess(cs.gson, groupid, "id"); } - @SuppressWarnings({ "null", "unused" }) @DELETE @Path("{username}/groups/{id}") @Operation(summary = "Deletes the item that is represented by this id", responses = { diff --git a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/Rules.java b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/Rules.java index bcb3ea774849a..6a83f2f1b0421 100644 --- a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/Rules.java +++ b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/Rules.java @@ -292,6 +292,10 @@ public Response modifyRuleApi(@Context UriInfo uri, // final HueRuleEntry changeRequest = cs.gson.fromJson(body, HueRuleEntry.class); + if (changeRequest == null) { + return NetworkUtils.singleError(cs.gson, uri, HueResponse.INVALID_JSON, "Empty body"); + } + Rule rule = ruleRegistry.remove(id); if (rule == null) { return NetworkUtils.singleError(cs.gson, uri, HueResponse.NOT_AVAILABLE, "Rule does not exist!"); @@ -333,7 +337,6 @@ public Response modifyRuleApi(@Context UriInfo uri, // )); } - @SuppressWarnings({ "null" }) @POST @Path("{username}/rules") @Operation(summary = "Create a new rule", responses = { @ApiResponse(responseCode = "200", description = "OK") }) @@ -353,10 +356,7 @@ public Response postNewRule(@Context UriInfo uri, String uid = UUID.randomUUID().toString(); RuleBuilder builder = RuleBuilder.create(uid).withName(newRuleData.name); - String description = newRuleData.description; - if (description != null) { - builder.withDescription(description); - } + builder.withDescription(newRuleData.description); try { builder.withActions(createActions(uid, newRuleData.actions, Collections.emptyList(), username)); diff --git a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/Scenes.java b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/Scenes.java index 82c2c93688761..a7b4c1d3d7443 100644 --- a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/Scenes.java +++ b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/Scenes.java @@ -18,7 +18,6 @@ import java.util.Map; import java.util.Objects; import java.util.UUID; -import java.util.stream.Collectors; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; @@ -178,7 +177,6 @@ public Response getScenesApi(@Context UriInfo uri, return Response.ok(cs.gson.toJson(cs.ds.scenes)).build(); } - @SuppressWarnings({ "unused", "null" }) @GET @Path("{username}/scenes/{id}") @Operation(summary = "Return a scene", responses = { @ApiResponse(responseCode = "200", description = "OK") }) @@ -193,7 +191,12 @@ public Response getSceneApi(@Context UriInfo uri, // return NetworkUtils.singleError(cs.gson, uri, HueResponse.NOT_AVAILABLE, "Scene does not exist!"); } HueSceneWithLightstates s = new HueSceneWithLightstates(sceneEntry); - for (String itemID : s.lights) { + List lights = s.lights; + if (lights == null) { + lights = List.of(); + } + + for (String itemID : lights) { Item item; try { item = itemRegistry.getItem(itemID); @@ -260,6 +263,10 @@ public Response modifySceneApi(@Context UriInfo uri, // final HueChangeSceneEntry changeRequest = cs.gson.fromJson(body, HueChangeSceneEntry.class); + if (changeRequest == null) { + return NetworkUtils.singleError(cs.gson, uri, HueResponse.INVALID_JSON, "Empty body"); + } + Rule rule = ruleRegistry.remove(id); if (rule == null) { return NetworkUtils.singleError(cs.gson, uri, HueResponse.NOT_AVAILABLE, "Scene does not exist!"); @@ -278,10 +285,8 @@ public Response modifySceneApi(@Context UriInfo uri, // List lights = changeRequest.lights; if (changeRequest.storelightstate && lights != null) { - @SuppressWarnings("null") - @NonNullByDefault({}) List actions = lights.stream().map(itemID -> itemRegistry.get(itemID)).filter(Objects::nonNull) - .map(item -> actionFromState(item.getUID(), item.getState())).collect(Collectors.toList()); + .map(item -> actionFromState(item.getUID(), item.getState())).toList(); builder.withActions(actions); } Map lightStates = changeRequest.lightstates; @@ -316,7 +321,6 @@ public Response modifySceneApi(@Context UriInfo uri, // )); } - @SuppressWarnings({ "null" }) @POST @Path("{username}/scenes") @Operation(summary = "Create a new scene", responses = { @ApiResponse(responseCode = "200", description = "OK") }) diff --git a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/Schedules.java b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/Schedules.java index 9f252cced124f..2949ddaef3bc9 100644 --- a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/Schedules.java +++ b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/Schedules.java @@ -313,7 +313,6 @@ public Response modifyScheduleApi(@Context UriInfo uri, // )); } - @SuppressWarnings({ "null" }) @POST @Path("{username}/schedules") @Operation(summary = "Create a new schedule", responses = { @@ -325,7 +324,13 @@ public Response postNewSchedule(@Context UriInfo uri, } HueScheduleEntry newScheduleData = cs.gson.fromJson(body, HueScheduleEntry.class); - if (newScheduleData == null || newScheduleData.name.isEmpty() || newScheduleData.localtime.isEmpty()) { + if (newScheduleData == null) { + return NetworkUtils.singleError(cs.gson, uri, HueResponse.INVALID_JSON, "Empty body"); + } + + String name = newScheduleData.name; + String localtime = newScheduleData.localtime; + if (name == null || name.isEmpty() || localtime == null || localtime.isEmpty()) { return NetworkUtils.singleError(cs.gson, uri, HueResponse.INVALID_JSON, "Invalid request: No name or localtime!"); } diff --git a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/Sensors.java b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/Sensors.java index 5f0fcd0a7e71e..64b822dad7767 100644 --- a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/Sensors.java +++ b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/Sensors.java @@ -197,7 +197,6 @@ public Response getSensorApi(@Context UriInfo uri, // return Response.ok(cs.gson.toJson(cs.ds.sensors.get(id))).build(); } - @SuppressWarnings({ "null", "unused" }) @GET @Path("{username}/sensors/{id}/config") @Operation(summary = "Return a sensor config. Always empty", responses = { @@ -217,7 +216,6 @@ public Response getSensorConfigApi(@Context UriInfo uri, // return Response.ok(cs.gson.toJson(sensor.config)).build(); } - @SuppressWarnings({ "null", "unused" }) @DELETE @Path("{username}/sensors/{id}") @Operation(summary = "Deletes the sensor that is represented by this id", responses = { @@ -242,7 +240,6 @@ public Response removeSensorAPI(@Context UriInfo uri, } } - @SuppressWarnings({ "null", "unused" }) @PUT @Path("{username}/sensors/{id}") @Operation(summary = "Rename a sensor", responses = { @ApiResponse(responseCode = "200", description = "OK") }) @@ -259,6 +256,10 @@ public Response renameLightApi(@Context UriInfo uri, // final HueChangeRequest changeRequest = cs.gson.fromJson(body, HueChangeRequest.class); + if (changeRequest == null) { + return NetworkUtils.singleError(cs.gson, uri, HueResponse.INVALID_JSON, "Empty body"); + } + String name = changeRequest.name; if (name == null || name.isEmpty()) { return NetworkUtils.singleError(cs.gson, uri, HueResponse.INVALID_JSON, "Invalid request: No name set"); diff --git a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/UserManagement.java b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/UserManagement.java index ff893c0d93f90..c9b98f8354b78 100644 --- a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/UserManagement.java +++ b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/rest/UserManagement.java @@ -91,7 +91,6 @@ public UserManagement(final @Reference StorageService storageService, final @Ref /** * Checks if the username exists in the whitelist */ - @SuppressWarnings("null") public boolean authorizeUser(String userName) { HueUserAuth userAuth = cs.ds.config.whitelist.get(userName); @@ -127,7 +126,6 @@ private void addUser(String apiKey, String clientKey, String label) { add(hueUserAuth); } - @SuppressWarnings("null") private synchronized void removeUser(String apiKey) { HueUserAuth userAuth = cs.ds.config.whitelist.remove(apiKey); if (userAuth != null) { @@ -161,8 +159,12 @@ public Response createNewUser(@Context UriInfo uri, String body) { "link button not pressed"); } - final HueCreateUser userRequest; - userRequest = cs.gson.fromJson(body, HueCreateUser.class); + final HueCreateUser userRequest = cs.gson.fromJson(body, HueCreateUser.class); + + if (userRequest == null) { + return NetworkUtils.singleError(cs.gson, uri, HueResponse.INVALID_JSON, "Empty body"); + } + if (userRequest.devicetype.isEmpty()) { return NetworkUtils.singleError(cs.gson, uri, HueResponse.INVALID_JSON, "Invalid request: No devicetype set"); diff --git a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/upnp/HueEmulationConfigWithRuntime.java b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/upnp/HueEmulationConfigWithRuntime.java index 2905d2c5e0afb..11ab2f15811db 100644 --- a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/upnp/HueEmulationConfigWithRuntime.java +++ b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/upnp/HueEmulationConfigWithRuntime.java @@ -17,6 +17,7 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.nio.channels.Selector; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; @@ -34,7 +35,7 @@ * @author David Graeff - Initial contribution */ @NonNullByDefault -class HueEmulationConfigWithRuntime extends Thread implements Runnable { +class HueEmulationConfigWithRuntime extends Thread { private final Logger logger = LoggerFactory.getLogger(HueEmulationConfigWithRuntime.class); @@ -66,7 +67,8 @@ class HueEmulationConfigWithRuntime extends Thread implements Runnable { multicastAddress = MULTI_ADDR_IPV4; } - port = config.discoveryHttpPort == 0 ? Integer.getInteger("org.osgi.service.http.port", 8080) + port = config.discoveryHttpPort == 0 + ? Objects.requireNonNull(Integer.getInteger("org.osgi.service.http.port", 8080)) : config.discoveryHttpPort; } diff --git a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/upnp/UpnpServer.java b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/upnp/UpnpServer.java index 025ac10e09f30..213248ca62e81 100644 --- a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/upnp/UpnpServer.java +++ b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/upnp/UpnpServer.java @@ -63,7 +63,6 @@ import org.osgi.service.component.annotations.Deactivate; import org.osgi.service.component.annotations.Reference; import org.osgi.service.event.Event; -import org.osgi.service.event.EventAdmin; import org.osgi.service.event.EventConstants; import org.osgi.service.event.EventHandler; import org.osgi.service.http.HttpService; @@ -179,14 +178,16 @@ protected void service(HttpServletRequest req, HttpServletResponse resp) throws */ @Activate protected void activate() { - InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream("discovery.xml"); - if (resourceAsStream == null) { - logger.warn("Could not start Hue Emulation service: discovery.xml not found"); - return; - } - try (InputStreamReader r = new InputStreamReader(resourceAsStream, StandardCharsets.UTF_8); - BufferedReader br = new BufferedReader(r)) { - xmlDoc = br.lines().collect(Collectors.joining("\n")); + try (InputStream resourceAsStream = UpnpServer.class.getResourceAsStream("/discovery.xml")) { + if (resourceAsStream == null) { + logger.warn("Could not start Hue Emulation service: discovery.xml not found"); + return; + } + + try (BufferedReader br = new BufferedReader( + new InputStreamReader(resourceAsStream, StandardCharsets.UTF_8))) { + xmlDoc = br.lines().collect(Collectors.joining("\n")); + } } catch (IOException e) { logger.warn("Could not start Hue Emulation UPNP server: {}", e.getMessage(), e); return; @@ -293,21 +294,18 @@ private void useAddressPort(HueEmulationConfigWithRuntime r) { /** * Create and return new runtime configuration based on {@link ConfigStore}s current configuration. - * Return null if the configuration has not changed compared to {@link #config}. * * @throws IllegalStateException If the {@link ConfigStore}s IP is invalid this exception is thrown. */ - protected @Nullable HueEmulationConfigWithRuntime createConfiguration( + protected HueEmulationConfigWithRuntime createConfiguration( @Nullable HueEmulationConfigWithRuntime ignoredParameter) throws IllegalStateException { - HueEmulationConfigWithRuntime r; try { - r = new HueEmulationConfigWithRuntime(this, cs.getConfig(), cs.ds.config.ipaddress, MULTI_ADDR_IPV4, + return new HueEmulationConfigWithRuntime(this, cs.getConfig(), cs.ds.config.ipaddress, MULTI_ADDR_IPV4, MULTI_ADDR_IPV6); } catch (UnknownHostException e) { logger.warn("The picked default IP address is not valid: {}", e.getMessage()); throw new IllegalStateException(e); } - return r; } /** @@ -317,7 +315,7 @@ private void useAddressPort(HueEmulationConfigWithRuntime r) { protected @Nullable HueEmulationConfigWithRuntime applyConfiguration( @Nullable HueEmulationConfigWithRuntime newRuntimeConfig) { if (newRuntimeConfig == null) { - return null;// Config hasn't changed + return null; // Config hasn't changed } config.dispose(); this.config = newRuntimeConfig; @@ -328,7 +326,7 @@ private void useAddressPort(HueEmulationConfigWithRuntime r) { /** * We have a hard dependency on the {@link ConfigStore} and that it has initialized the Hue DataStore config * completely. That initialization happens asynchronously and therefore we cannot rely on OSGi activate/modified - * state changes. Instead the {@link EventAdmin} is used and we listen for the + * state changes. Instead the {@link org.osgi.service.event.EventAdmin} is used and we listen for the * {@link ConfigStore#EVENT_ADDRESS_CHANGED} event that is fired as soon as the config is ready. *

* To be really sure that we are called here, this is also issued by the main service after it has received the @@ -349,8 +347,12 @@ public synchronized void handleEvent(@Nullable Event event) { } configChangeFuture = root.thenApply(this::createConfiguration) .thenApplyAsync(this::performAddressTest, executor).thenApply(this::applyConfiguration) - .thenCompose(c -> c.startNow()) - .whenComplete((HueEmulationConfigWithRuntime config, @Nullable Throwable e) -> { + .thenCompose(c -> { + if (c == null) { + return CompletableFuture.completedFuture(null); + } + return c.startNow(); + }).whenComplete((HueEmulationConfigWithRuntime config, @Nullable Throwable e) -> { if (e != null) { logger.warn("Upnp server: Address test failed", e); } @@ -446,14 +448,14 @@ public void accept(HueEmulationConfigWithRuntime threadContext) { return; } - if (hasIPv4) { + if (hasIPv4 && channelV4 != null) { channelV4.configureBlocking(false); channelV4.register(selector, SelectionKey.OP_READ, new ClientRecord()); try (DatagramSocket sendSocket = new DatagramSocket(new InetSocketAddress(config.address, 0))) { sendUPNPDatagrams(sendSocket, MULTI_ADDR_IPV4, UPNP_PORT); } } - if (hasIPv6) { + if (hasIPv6 && channelV6 != null) { channelV6.configureBlocking(false); channelV6.register(selector, SelectionKey.OP_READ, new ClientRecord()); try (DatagramSocket sendSocket = new DatagramSocket()) { diff --git a/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/ItemUIDtoHueIDMappingTests.java b/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/ItemUIDtoHueIDMappingTests.java index d27761bb16975..dc0107bd6b19a 100644 --- a/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/ItemUIDtoHueIDMappingTests.java +++ b/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/ItemUIDtoHueIDMappingTests.java @@ -14,6 +14,7 @@ import static org.hamcrest.CoreMatchers.*; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.Mockito.mock; import java.io.IOException; @@ -91,6 +92,7 @@ public void mapItemWithoutHueID() { assertThat(hueID, CoreMatchers.is("2")); HueLightEntry device = cs.ds.lights.get(hueID); + assertNotNull(device); assertThat(device.item, is(item)); assertThat(device.state, is(instanceOf(HueStatePlug.class))); @@ -111,6 +113,7 @@ public void mapItemWithHueID() { assertThat(hueID, CoreMatchers.is("10")); HueLightEntry device = cs.ds.lights.get(hueID); + assertNotNull(device); assertThat(device.item, is(item)); assertThat(device.state, is(instanceOf(HueStatePlug.class))); @@ -131,6 +134,7 @@ public void uniqueIdForLargeHueID() { assertThat(hueID, CoreMatchers.is("255")); HueLightEntry device = cs.ds.lights.get(hueID); + assertNotNull(device); assertThat(device.item, is(item)); assertThat(device.state, is(instanceOf(HueStatePlug.class))); assertThat(device.uniqueid, CoreMatchers.is("00:00:ff:00:00:ff:00:00-ff")); @@ -144,6 +148,7 @@ public void uniqueIdForLargeHueID() { assertThat(hueID, CoreMatchers.is("256000")); device = cs.ds.lights.get(hueID); + assertNotNull(device); assertThat(device.item, is(item)); assertThat(device.state, is(instanceOf(HueStatePlug.class))); assertThat(device.uniqueid, CoreMatchers.is("03:e8:00:03:e8:00:03:e8-00")); diff --git a/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/LightsAndGroupsTests.java b/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/LightsAndGroupsTests.java index e2ad4fd450438..d5f2ca39680b3 100644 --- a/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/LightsAndGroupsTests.java +++ b/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/LightsAndGroupsTests.java @@ -14,7 +14,8 @@ import static org.hamcrest.CoreMatchers.*; import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.verify; @@ -92,6 +93,7 @@ public void addSwitchableByCategory() { item.setCategory("Light"); itemRegistry.add(item); HueLightEntry device = cs.ds.lights.get(cs.mapItemUIDtoHueID(item)); + assertNotNull(device); assertThat(device.item, is(item)); assertThat(device.state, is(instanceOf(HueStatePlug.class))); } @@ -102,6 +104,7 @@ public void addSwitchableByTag() { item.addTag("Switchable"); itemRegistry.add(item); HueLightEntry device = cs.ds.lights.get(cs.mapItemUIDtoHueID(item)); + assertNotNull(device); assertThat(device.item, is(item)); assertThat(device.state, is(instanceOf(HueStatePlug.class))); } @@ -121,6 +124,7 @@ public void addGroupSwitchableByTag() { item.addTag("Switchable"); itemRegistry.add(item); HueGroupEntry device = cs.ds.groups.get(cs.mapItemUIDtoHueID(item)); + assertNotNull(device); assertThat(device.groupItem, is(item)); assertThat(device.action, is(instanceOf(HueStatePlug.class))); } @@ -132,6 +136,7 @@ public void addDeviceAsGroupSwitchableByTag() { item.addTag("Huelight"); itemRegistry.add(item); HueLightEntry device = cs.ds.lights.get(cs.mapItemUIDtoHueID(item)); + assertNotNull(device); assertThat(device.item, is(item)); assertThat(device.state, is(instanceOf(HueStatePlug.class))); } @@ -144,9 +149,10 @@ public void addGroupWithoutTypeByTag() { itemRegistry.add(item); HueGroupEntry device = cs.ds.groups.get(cs.mapItemUIDtoHueID(item)); + assertNotNull(device); assertThat(device.groupItem, is(item)); assertThat(device.action, is(instanceOf(HueStatePlug.class))); - assertThat(cs.ds.groups.get(cs.mapItemUIDtoHueID(item)).groupItem, is(item)); + assertThat(device.groupItem, is(item)); } @Test @@ -187,6 +193,7 @@ public void updateSwitchable() { itemRegistry.add(item); String hueID = cs.mapItemUIDtoHueID(item); HueLightEntry device = cs.ds.lights.get(hueID); + assertNotNull(device); assertThat(device.item, is(item)); assertThat(device.state, is(instanceOf(HueStatePlug.class))); assertThat(device.name, is("labelOld")); @@ -196,6 +203,7 @@ public void updateSwitchable() { newitem.addTag("Switchable"); subject.updated(item, newitem); device = cs.ds.lights.get(hueID); + assertNotNull(device); assertThat(device.item, is(newitem)); assertThat(device.state, is(instanceOf(HueStatePlug.class))); assertThat(device.name, is("labelNew")); @@ -209,6 +217,7 @@ public void updateSwitchableNoTags() { itemRegistry.add(item); String hueID = cs.mapItemUIDtoHueID(item); HueLightEntry device = cs.ds.lights.get(hueID); + assertNotNull(device); assertThat(device.item, is(item)); assertThat(device.state, is(instanceOf(HueStatePlug.class))); assertThat(device.name, is("labelOld")); @@ -230,6 +239,7 @@ public void updateSwitchableUnsupportedItemType() { itemRegistry.add(item); String hueID = cs.mapItemUIDtoHueID(item); HueLightEntry device = cs.ds.lights.get(hueID); + assertNotNull(device); assertThat(device.item, is(item)); assertThat(device.state, is(instanceOf(HueStatePlug.class))); assertThat(device.name, is("label")); @@ -245,13 +255,19 @@ public void updateSwitchableUnsupportedItemType() { @Test public void changeSwitchState() throws Exception { - assertThat(((HueStatePlug) cs.ds.lights.get("1").state).on, is(false)); + HueLightEntry hueLightEntry = cs.ds.lights.get("1"); + assertNotNull(hueLightEntry); + HueStatePlug statePlug = assertInstanceOf(HueStatePlug.class, hueLightEntry.state); + assertThat(statePlug.on, is(false)); String body = "{'on':true}"; ContentResponse response = commonSetup.sendPut("/testuser/lights/1/state", body); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); assertThat(response.getContentAsString(), containsString("success")); - assertThat(((HueStatePlug) cs.ds.lights.get("1").state).on, is(true)); + hueLightEntry = cs.ds.lights.get("1"); + assertNotNull(hueLightEntry); + statePlug = assertInstanceOf(HueStatePlug.class, hueLightEntry.state); + assertThat(statePlug.on, is(true)); verify(commonSetup.eventPublisher).post(argThat((Event t) -> { assertThat(t.getPayload(), is("{\"type\":\"OnOff\",\"value\":\"ON\"}")); return true; @@ -260,13 +276,19 @@ public void changeSwitchState() throws Exception { @Test public void changeGroupItemSwitchState() throws Exception { - assertThat(((HueStatePlug) cs.ds.groups.get("10").action).on, is(false)); + HueGroupEntry hueGroupEntry = cs.ds.groups.get("10"); + assertNotNull(hueGroupEntry); + HueStatePlug statePlug = assertInstanceOf(HueStatePlug.class, hueGroupEntry.action); + assertThat(statePlug.on, is(false)); String body = "{'on':true}"; ContentResponse response = commonSetup.sendPut("/testuser/groups/10/action", body); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); assertThat(response.getContentAsString(), containsString("success")); - assertThat(((HueStatePlug) cs.ds.groups.get("10").action).on, is(true)); + hueGroupEntry = cs.ds.groups.get("10"); + assertNotNull(hueGroupEntry); + statePlug = assertInstanceOf(HueStatePlug.class, hueGroupEntry.action); + assertThat(statePlug.on, is(true)); verify(commonSetup.eventPublisher).post(argThat((Event t) -> { assertThat(t.getPayload(), is("{\"type\":\"OnOff\",\"value\":\"ON\"}")); return true; @@ -275,42 +297,58 @@ public void changeGroupItemSwitchState() throws Exception { @Test public void changeOnValue() throws Exception { - assertThat(((HueStateColorBulb) cs.ds.lights.get("2").state).on, is(false)); + HueLightEntry hueLightEntry = cs.ds.lights.get("2"); + assertNotNull(hueLightEntry); + HueStateColorBulb stateColorBulb = assertInstanceOf(HueStateColorBulb.class, hueLightEntry.state); + assertThat(stateColorBulb.on, is(false)); String body = "{'on':true}"; ContentResponse response = commonSetup.sendPut("/testuser/lights/2/state", body); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); String entity = response.getContentAsString(); assertThat(entity, is("[{\"success\":{\"/lights/2/state/on\":true}}]")); - assertThat(((HueStateColorBulb) cs.ds.lights.get("2").state).on, is(true)); + hueLightEntry = cs.ds.lights.get("2"); + assertNotNull(hueLightEntry); + stateColorBulb = assertInstanceOf(HueStateColorBulb.class, hueLightEntry.state); + assertThat(stateColorBulb.on, is(true)); } @Test public void changeOnAndBriValues() throws Exception { - assertThat(((HueStateColorBulb) cs.ds.lights.get("2").state).on, is(false)); - assertThat(((HueStateColorBulb) cs.ds.lights.get("2").state).bri, is(1)); + HueLightEntry hueLightEntry = cs.ds.lights.get("2"); + assertNotNull(hueLightEntry); + HueStateColorBulb stateColorBulb = assertInstanceOf(HueStateColorBulb.class, hueLightEntry.state); + assertThat(stateColorBulb.on, is(false)); + assertThat(stateColorBulb.bri, is(1)); String body = "{'on':true,'bri':200}"; ContentResponse response = commonSetup.sendPut("/testuser/lights/2/state", body); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); assertThat(response.getContentAsString(), containsString("success")); - assertThat(((HueStateColorBulb) cs.ds.lights.get("2").state).on, is(true)); - assertThat(((HueStateColorBulb) cs.ds.lights.get("2").state).bri, is(200)); + hueLightEntry = cs.ds.lights.get("2"); + assertNotNull(hueLightEntry); + stateColorBulb = assertInstanceOf(HueStateColorBulb.class, hueLightEntry.state); + assertThat(stateColorBulb.on, is(true)); + assertThat(stateColorBulb.bri, is(200)); } @Test public void changeHueSatValues() throws Exception { - HueLightEntry hueDevice = cs.ds.lights.get("2"); - hueDevice.item.setState(OnOffType.ON); - hueDevice.state.as(HueStateColorBulb.class).on = true; + HueLightEntry hueLightEntry = cs.ds.lights.get("2"); + assertNotNull(hueLightEntry); + hueLightEntry.item.setState(OnOffType.ON); + hueLightEntry.state.as(HueStateColorBulb.class).on = true; String body = "{'hue':1000,'sat':50}"; ContentResponse response = commonSetup.sendPut("/testuser/lights/2/state", body); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); assertThat(response.getContentAsString(), containsString("success")); - assertThat(((HueStateColorBulb) cs.ds.lights.get("2").state).on, is(true)); - assertThat(((HueStateColorBulb) cs.ds.lights.get("2").state).hue, is(1000)); - assertThat(((HueStateColorBulb) cs.ds.lights.get("2").state).sat, is(50)); + hueLightEntry = cs.ds.lights.get("2"); + assertNotNull(hueLightEntry); + HueStateColorBulb stateColorBulb = assertInstanceOf(HueStateColorBulb.class, hueLightEntry.state); + assertThat(stateColorBulb.on, is(true)); + assertThat(stateColorBulb.hue, is(1000)); + assertThat(stateColorBulb.sat, is(50)); verify(commonSetup.eventPublisher).post(argThat(ce -> assertHueValue((ItemCommandEvent) ce, 1000))); } @@ -320,19 +358,23 @@ public void changeHueSatValues() throws Exception { */ @Test public void changeCtValue() throws Exception { - HueLightEntry hueDevice = cs.ds.lights.get("2"); - hueDevice.item.setState(OnOffType.ON); - hueDevice.state.as(HueStateColorBulb.class).on = true; + HueLightEntry hueLightEntry = cs.ds.lights.get("2"); + assertNotNull(hueLightEntry); + hueLightEntry.item.setState(OnOffType.ON); + hueLightEntry.state.as(HueStateColorBulb.class).on = true; String body = "{'ct':500}"; ContentResponse response = commonSetup.sendPut("/testuser/lights/2/state", body); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); body = response.getContentAsString(); assertThat(body, containsString("success")); assertThat(body, containsString("ct")); - assertThat(((HueStateColorBulb) cs.ds.lights.get("2").state).on, is(true)); - assertThat(((HueStateColorBulb) cs.ds.lights.get("2").state).ct, is(500)); - assertThat(((HueStateColorBulb) cs.ds.lights.get("2").state).sat, is(0)); + hueLightEntry = cs.ds.lights.get("2"); + assertNotNull(hueLightEntry); + HueStateColorBulb stateColorBulb = assertInstanceOf(HueStateColorBulb.class, hueLightEntry.state); + assertThat(stateColorBulb.on, is(true)); + assertThat(stateColorBulb.ct, is(500)); + assertThat(stateColorBulb.sat, is(0)); // Saturation is expected to be 0 -> white light verify(commonSetup.eventPublisher).post(argThat(ce -> assertSatValue((ItemCommandEvent) ce, 0))); @@ -340,29 +382,34 @@ public void changeCtValue() throws Exception { @Test public void switchOnWithXY() throws Exception { - assertThat(((HueStateColorBulb) cs.ds.lights.get("2").state).on, is(false)); - assertThat(((HueStateColorBulb) cs.ds.lights.get("2").state).bri, is(1)); + HueLightEntry hueLightEntry = cs.ds.lights.get("2"); + assertNotNull(hueLightEntry); + HueStateColorBulb stateColorBulb = assertInstanceOf(HueStateColorBulb.class, hueLightEntry.state); + assertThat(stateColorBulb.on, is(false)); + assertThat(stateColorBulb.bri, is(1)); String body = "{'on':true,'bri':200,'xy':[0.5119,0.4147]}"; ContentResponse response = commonSetup.sendPut("/testuser/lights/2/state", body); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); assertThat(response.getContentAsString(), containsString("success")); assertThat(response.getContentAsString(), containsString("xy")); - assertThat(((HueStateColorBulb) cs.ds.lights.get("2").state).on, is(true)); - assertThat(((HueStateColorBulb) cs.ds.lights.get("2").state).bri, is(200)); - assertThat(((HueStateColorBulb) cs.ds.lights.get("2").state).xy[0], is(0.5119)); - assertThat(((HueStateColorBulb) cs.ds.lights.get("2").state).xy[1], is(0.4147)); - assertThat(((HueStateColorBulb) cs.ds.lights.get("2").state).colormode, is(HueStateColorBulb.ColorMode.xy)); - assertThat(((HueStateColorBulb) cs.ds.lights.get("2").state).toHSBType().getHue().intValue(), - is((int) 27.47722590981918)); - assertThat(((HueStateColorBulb) cs.ds.lights.get("2").state).toHSBType().getSaturation().intValue(), is(88)); - assertThat(((HueStateColorBulb) cs.ds.lights.get("2").state).toHSBType().getBrightness().intValue(), is(78)); + hueLightEntry = cs.ds.lights.get("2"); + assertNotNull(hueLightEntry); + stateColorBulb = assertInstanceOf(HueStateColorBulb.class, hueLightEntry.state); + assertThat(stateColorBulb.on, is(true)); + assertThat(stateColorBulb.bri, is(200)); + assertThat(stateColorBulb.xy[0], is(0.5119)); + assertThat(stateColorBulb.xy[1], is(0.4147)); + assertThat(stateColorBulb.colormode, is(HueStateColorBulb.ColorMode.xy)); + assertThat(stateColorBulb.toHSBType().getHue().intValue(), is((int) 27.47722590981918)); + assertThat(stateColorBulb.toHSBType().getSaturation().intValue(), is(88)); + assertThat(stateColorBulb.toHSBType().getBrightness().intValue(), is(78)); } @Test public void allLightsAndSingleLight() throws Exception { ContentResponse response = commonSetup.sendGet("/testuser/lights"); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); String body = response.getContentAsString(); @@ -372,7 +419,7 @@ public void allLightsAndSingleLight() throws Exception { // Single light access test response = commonSetup.sendGet("/testuser/lights/2"); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); body = response.getContentAsString(); assertThat(body, containsString("color")); } diff --git a/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/RulesTests.java b/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/RulesTests.java index 079db858b6093..7f12385ad3c2b 100644 --- a/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/RulesTests.java +++ b/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/RulesTests.java @@ -128,6 +128,7 @@ public void addUpdateRemoveScheduleToRegistry() { // Check hue entry HueRuleEntry entry = cs.ds.rules.get("demo1"); + assertNotNull(entry); assertThat(entry.conditions.get(0).address, is("/lights/switch1/state/on")); assertThat(entry.conditions.get(0).operator, is(Operator.dx)); assertThat(entry.actions.get(0).address, is("/lights/switch1/state")); @@ -142,6 +143,7 @@ public void addUpdateRemoveScheduleToRegistry() { ruleRegistry.update(rule); entry = cs.ds.rules.get("demo1"); + assertNotNull(entry); assertThat(entry.actions.get(0).address, is("/lights/switch2/state")); assertThat(entry.actions.get(0).method, is("PUT")); assertThat(entry.actions.get(0).body, is("{'on':false}")); @@ -154,13 +156,12 @@ public void addUpdateRemoveScheduleToRegistry() { assertThat(entry, nullValue()); } - @SuppressWarnings("null") @Test public void addGetRemoveRuleViaRest() throws Exception { // 1. Create String body = "{\"name\":\"test name\",\"description\":\"\",\"owner\":\"\",\"conditions\":[{\"address\":\"/lights/switch1/state/on\",\"operator\":\"dx\"}],\"actions\":[{\"address\":\"/lights/switch1/state\",\"method\":\"PUT\",\"body\":\"{\\u0027on\\u0027:true}\"}]}"; ContentResponse response = commonSetup.sendPost("/testuser/rules", body); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); assertThat(response.getContentAsString(), containsString("success")); // 1.1 Check for entry @@ -172,19 +173,21 @@ public void addGetRemoveRuleViaRest() throws Exception { // 1.2 Check for rule Rule rule = ruleRegistry.get(idAndEntry.getKey()); + assertNotNull(rule); assertThat(rule.getName(), is("test name")); assertThat(rule.getActions().get(0).getId(), is("-api-testuser-lights-switch1-state")); assertThat(rule.getActions().get(0).getTypeUID(), is("rules.HttpAction")); // 2. Get response = commonSetup.sendGet("/testuser/rules/" + idAndEntry.getKey()); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); HueSceneEntry fromJson = new Gson().fromJson(response.getContentAsString(), HueSceneEntry.class); + assertNotNull(fromJson); assertThat(fromJson.name, is(idAndEntry.getValue().name)); // 3. Remove response = commonSetup.sendDelete("/testuser/rules/" + idAndEntry.getKey()); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); assertTrue(cs.ds.rules.isEmpty()); } @@ -205,7 +208,7 @@ public void updateRuleViaRest() throws Exception { // Modify (just the name) String body = "{ 'name':'A new name'}"; ContentResponse response = commonSetup.sendPut("/testuser/rules/demo1", body); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); assertThat(response.getContentAsString(), containsString("name")); Entry idAndEntry = cs.ds.rules.entrySet().stream().findAny().get(); @@ -226,7 +229,7 @@ public void updateRuleViaRest() throws Exception { // Modify (Change condition) body = "{\"conditions\":[{\"address\":\"/lights/switch1/state/on\",\"operator\":\"ddx\"}]}"; response = commonSetup.sendPut("/testuser/rules/demo1", body); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); assertThat(response.getContentAsString(), containsString("conditions")); idAndEntry = cs.ds.rules.entrySet().stream().findAny().get(); @@ -237,7 +240,7 @@ public void updateRuleViaRest() throws Exception { // Modify (Change action) body = "{\"actions\":[{\"address\":\"/lights/switch2/state\",\"method\":\"PUT\",\"body\":\"{\\u0027on\\u0027:false}\"}]}"; response = commonSetup.sendPut("/testuser/rules/demo1", body); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); assertThat(response.getContentAsString(), containsString("actions")); idAndEntry = cs.ds.rules.entrySet().stream().findAny().get(); @@ -265,7 +268,9 @@ public void getAll() throws Exception { }.getType(); String body = response.getContentAsString(); Map fromJson = new Gson().fromJson(body, type); + assertNotNull(fromJson); HueRuleEntry entry = fromJson.get("demo1"); + assertNotNull(entry); assertThat(entry.name, is("test name")); assertThat(entry.actions.get(0).address, is("/lights/switch1/state")); assertThat(entry.conditions.get(0).address, is("/lights/switch1/state/on")); diff --git a/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/SceneTests.java b/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/SceneTests.java index 84de99ff2e125..468e6a02e692a 100644 --- a/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/SceneTests.java +++ b/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/SceneTests.java @@ -18,6 +18,7 @@ import java.io.IOException; import java.lang.reflect.Type; +import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -101,7 +102,6 @@ public void tearDown() throws Exception { commonSetup.dispose(); } - @SuppressWarnings("null") @Test public void addUpdateRemoveSceneToRegistry() { Rule rule = RuleBuilder.create("demo1").withTags("scene") // @@ -110,7 +110,12 @@ public void addUpdateRemoveSceneToRegistry() { ruleRegistry.add(rule); HueSceneEntry sceneEntry = cs.ds.scenes.get("demo1"); - assertThat(sceneEntry.lights.get(0), CoreMatchers.is("switch1")); + assertNotNull(sceneEntry); + List lights = sceneEntry.lights; + assertNotNull(lights); + String light = lights.get(0); + assertNotNull(light); + assertThat(light, CoreMatchers.is("switch1")); // Update rule = RuleBuilder.create("demo1").withTags("scene") // @@ -118,7 +123,12 @@ public void addUpdateRemoveSceneToRegistry() { ruleRegistry.update(rule); sceneEntry = cs.ds.scenes.get("demo1"); - assertThat(sceneEntry.lights.get(0), CoreMatchers.is("white1")); + assertNotNull(sceneEntry); + lights = sceneEntry.lights; + assertNotNull(lights); + light = lights.get(0); + assertNotNull(light); + assertThat(light, CoreMatchers.is("white1")); // Remove @@ -127,40 +137,51 @@ public void addUpdateRemoveSceneToRegistry() { assertThat(sceneEntry, CoreMatchers.nullValue()); } - @SuppressWarnings("null") @Test public void addGetRemoveSceneViaRest() throws Exception { // 1. Create String body = "{ 'name':'Cozy dinner', 'recycle':false, 'lights':['switch1','white1'], 'type':'LightScene'}"; ContentResponse response = commonSetup.sendPost("/testuser/scenes", body); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); assertThat(response.getContentAsString(), containsString("success")); // 1.1 Check for scene entry Entry entry = cs.ds.scenes.entrySet().stream().findAny().get(); + assertNotNull(entry); assertThat(entry.getValue().name, is("Cozy dinner")); - assertThat(entry.getValue().lights.get(0), is("switch1")); - assertThat(entry.getValue().lights.get(1), is("white1")); + List lights = entry.getValue().lights; + assertNotNull(lights); + lights = entry.getValue().lights; + assertNotNull(lights); + String light = lights.get(0); + assertNotNull(light); + assertThat(light, is("switch1")); + lights = entry.getValue().lights; + assertNotNull(lights); + light = lights.get(1); + assertNotNull(light); + assertThat(light, is("white1")); // 1.2 Check for rule Rule rule = ruleRegistry.get(entry.getKey()); + assertNotNull(rule); assertThat(rule.getName(), is("Cozy dinner")); assertThat(rule.getActions().get(0).getId(), is("switch1")); assertThat(rule.getActions().get(1).getId(), is("white1")); // 2. Get response = commonSetup.sendGet("/testuser/scenes/" + entry.getKey()); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); HueSceneEntry fromJson = new Gson().fromJson(response.getContentAsString(), HueSceneEntry.class); + assertNotNull(fromJson); assertThat(fromJson.name, is(entry.getValue().name)); // 3. Remove response = commonSetup.sendDelete("/testuser/scenes/" + entry.getKey()); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); assertTrue(cs.ds.scenes.isEmpty()); } - @SuppressWarnings("null") @Test public void updateSceneViaRest() throws Exception { Rule rule = RuleBuilder.create("demo1").withTags("scene").withName("Some name") // @@ -171,12 +192,17 @@ public void updateSceneViaRest() throws Exception { // 3. Modify (just the name) String body = "{ 'name':'A new name'}"; ContentResponse response = commonSetup.sendPut("/testuser/scenes/demo1", body); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); assertThat(response.getContentAsString(), containsString("name")); Entry sceneEntry = cs.ds.scenes.entrySet().stream().findAny().get(); + assertNotNull(sceneEntry); assertThat(sceneEntry.getValue().name, is("A new name")); - assertThat(sceneEntry.getValue().lights.get(0), is("switch1")); // nothing else should have changed + List lights = sceneEntry.getValue().lights; + assertNotNull(lights); + String light = lights.get(0); + assertNotNull(light); + assertThat(light, is("switch1")); // nothing else should have changed // 3. Modify (just the lights) rule = RuleBuilder.create("demo1").withTags("scene").withName("Some name") // @@ -190,22 +216,32 @@ public void updateSceneViaRest() throws Exception { // Without store lights body = "{ 'lights':['white1']}"; response = commonSetup.sendPut("/testuser/scenes/demo1", body); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); assertThat(response.getContentAsString(), containsString("lights")); sceneEntry = cs.ds.scenes.entrySet().stream().findAny().get(); + assertNotNull(sceneEntry); assertThat(sceneEntry.getValue().name, is("Some name")); // should not have changed assertThat(sceneEntry.getKey(), is(uid)); - assertThat(sceneEntry.getValue().lights.get(0), is("switch1")); // storelightstate not set, lights not changed + lights = sceneEntry.getValue().lights; + assertNotNull(lights); + light = lights.get(0); + assertNotNull(light); + assertThat(light, is("switch1")); // storelightstate not set, lights not changed // With store lights body = "{ 'lights':['white1'], 'storelightstate':true }"; response = commonSetup.sendPut("/testuser/scenes/demo1", body); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); assertThat(response.getContentAsString(), containsString("lights")); sceneEntry = cs.ds.scenes.entrySet().stream().findAny().get(); - assertThat(sceneEntry.getValue().lights.get(0), is("white1")); + assertNotNull(sceneEntry); + lights = sceneEntry.getValue().lights; + assertNotNull(lights); + light = lights.get(0); + assertNotNull(light); + assertThat(light, is("white1")); } @Test @@ -219,6 +255,7 @@ public void getAll() throws Exception { Type type = new TypeToken>() { }.getType(); Map fromJson = new Gson().fromJson(response.getContentAsString(), type); + assertNotNull(fromJson); assertTrue(fromJson.containsKey("demo1")); } } diff --git a/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/ScheduleTests.java b/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/ScheduleTests.java index f755522e6cc01..5a0d6ee90e86e 100644 --- a/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/ScheduleTests.java +++ b/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/ScheduleTests.java @@ -102,7 +102,6 @@ public void tearDown() throws Exception { commonSetup.dispose(); } - @SuppressWarnings("null") @Test public void addUpdateRemoveScheduleToRegistry() { HueCommand command = new HueCommand("/api/testuser/lights/1/state", "PUT", "{'on':true}"); @@ -116,9 +115,12 @@ public void addUpdateRemoveScheduleToRegistry() { // Check hue entry HueScheduleEntry sceneEntry = cs.ds.schedules.get("demo1"); - assertThat(sceneEntry.command.address, is("/api/testuser/lights/1/state")); - assertThat(sceneEntry.command.method, is("PUT")); - assertThat(sceneEntry.command.body, is("{'on':true}")); + assertNotNull(sceneEntry); + command = sceneEntry.command; + assertNotNull(command); + assertThat(command.address, is("/api/testuser/lights/1/state")); + assertThat(command.method, is("PUT")); + assertThat(command.body, is("{'on':true}")); assertThat(sceneEntry.localtime, is(localtime)); // Update @@ -129,7 +131,10 @@ public void addUpdateRemoveScheduleToRegistry() { ruleRegistry.update(rule); sceneEntry = cs.ds.schedules.get("demo1"); - assertThat(sceneEntry.command.address, is("/api/testuser/lights/1/state")); + assertNotNull(sceneEntry); + command = sceneEntry.command; + assertNotNull(command); + assertThat(command.address, is("/api/testuser/lights/1/state")); assertThat(sceneEntry.localtime, is(localtime)); // Remove @@ -139,43 +144,46 @@ public void addUpdateRemoveScheduleToRegistry() { assertThat(sceneEntry, nullValue()); } - @SuppressWarnings("null") @Test public void addGetRemoveScheduleViaRest() throws Exception { // 1. Create String body = "{ 'name':'Wake up', 'description':'My wake up alarm', 'localtime':'2015-06-30T14:24:40'," + // "'command':{'address':'/api/testuser/lights/1/state','method':'PUT','body':'{\"on\":true}'} }"; ContentResponse response = commonSetup.sendPost("/testuser/schedules", body); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); assertThat(response.getContentAsString(), containsString("success")); // 1.1 Check for entry Entry entry = cs.ds.schedules.entrySet().stream().findAny().get(); + assertNotNull(entry); assertThat(entry.getValue().name, is("Wake up")); - assertThat(entry.getValue().command.address, is("/api/testuser/lights/1/state")); - assertThat(entry.getValue().command.method, is("PUT")); - assertThat(entry.getValue().command.body, is("{\"on\":true}")); + HueCommand command = entry.getValue().command; + assertNotNull(command); + assertThat(command.address, is("/api/testuser/lights/1/state")); + assertThat(command.method, is("PUT")); + assertThat(command.body, is("{\"on\":true}")); assertThat(entry.getValue().localtime, is("2015-06-30T14:24:40")); // 1.2 Check for rule Rule rule = ruleRegistry.get(entry.getKey()); + assertNotNull(rule); assertThat(rule.getName(), is("Wake up")); assertThat(rule.getActions().get(0).getId(), is("command")); assertThat(rule.getActions().get(0).getTypeUID(), is("rules.HttpAction")); // 2. Get response = commonSetup.sendGet("/testuser/schedules/" + entry.getKey()); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); HueSceneEntry fromJson = new Gson().fromJson(response.getContentAsString(), HueSceneEntry.class); + assertNotNull(fromJson); assertThat(fromJson.name, is(entry.getValue().name)); // 3. Remove response = commonSetup.sendDelete("/testuser/schedules/" + entry.getKey()); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); assertTrue(cs.ds.schedules.isEmpty()); } - @SuppressWarnings("null") @Test public void updateScheduleViaRest() throws Exception { HueCommand command = new HueCommand("/api/testuser/lights/1/state", "PUT", "{'on':true}"); @@ -190,13 +198,16 @@ public void updateScheduleViaRest() throws Exception { // Modify (just the name) String body = "{ 'name':'A new name'}"; ContentResponse response = commonSetup.sendPut("/testuser/schedules/demo1", body); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); assertThat(response.getContentAsString(), containsString("name")); Entry entry = cs.ds.schedules.entrySet().stream().findAny().get(); + assertNotNull(entry); assertThat(entry.getValue().name, is("A new name")); - assertThat(entry.getValue().command.address, is("/api/testuser/lights/1/state")); // nothing else should have - // changed + command = entry.getValue().command; + assertNotNull(command); + // nothing else should have changed + assertThat(command.address, is("/api/testuser/lights/1/state")); assertThat(entry.getValue().localtime, is(localtime)); // Reset @@ -212,10 +223,11 @@ public void updateScheduleViaRest() throws Exception { // Modify (Change time) body = "{ 'localtime':'2015-06-30T14:24:40'}"; response = commonSetup.sendPut("/testuser/schedules/demo1", body); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); assertThat(response.getContentAsString(), containsString("localtime")); entry = cs.ds.schedules.entrySet().stream().findAny().get(); + assertNotNull(entry); assertThat(entry.getValue().name, is("test name")); // should not have changed assertThat(entry.getKey(), is(uid)); assertThat(entry.getValue().localtime, is("2015-06-30T14:24:40")); @@ -223,13 +235,16 @@ public void updateScheduleViaRest() throws Exception { // Modify (Change command) body = "{ 'command':{'address':'/api/testuser/lights/2/state','method':'PUT','body':'{\"on\":true}'} }"; response = commonSetup.sendPut("/testuser/schedules/demo1", body); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); assertThat(response.getContentAsString(), containsString("command")); entry = cs.ds.schedules.entrySet().stream().findAny().get(); + assertNotNull(entry); assertThat(entry.getValue().name, is("test name")); // should not have changed assertThat(entry.getKey(), is(uid)); - assertThat(entry.getValue().command.address, is("/api/testuser/lights/2/state")); + command = entry.getValue().command; + assertNotNull(command); + assertThat(command.address, is("/api/testuser/lights/2/state")); } @Test @@ -247,6 +262,7 @@ public void getAll() throws Exception { Type type = new TypeToken>() { }.getType(); Map fromJson = new Gson().fromJson(response.getContentAsString(), type); + assertNotNull(fromJson); assertTrue(fromJson.containsKey("demo1")); } diff --git a/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/SensorTests.java b/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/SensorTests.java index c4a64977793a0..692ce6cf1c1d5 100644 --- a/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/SensorTests.java +++ b/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/SensorTests.java @@ -14,7 +14,7 @@ import static org.hamcrest.CoreMatchers.*; import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jetty.client.HttpClient; @@ -38,6 +38,7 @@ import org.openhab.core.library.types.PercentType; import org.openhab.core.types.State; import org.openhab.io.hueemulation.internal.ConfigStore; +import org.openhab.io.hueemulation.internal.dto.HueSensorEntry; import org.openhab.io.hueemulation.internal.rest.mocks.DummyItemRegistry; /** @@ -94,23 +95,27 @@ public void tearDown() throws Exception { @Test public void renameSensor() throws Exception { - assertThat(cs.ds.sensors.get("switch1").name, is("name1")); + HueSensorEntry sensorEntry = cs.ds.sensors.get("switch1"); + assertNotNull(sensorEntry); + assertThat(sensorEntry.name, is("name1")); String body = "{'name':'name2'}"; ContentResponse response = commonSetup.sendPut("/testuser/sensors/switch1", body); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); body = response.getContentAsString(); assertThat(body, containsString("success")); assertThat(body, containsString("name")); - assertThat(cs.ds.sensors.get("switch1").name, is("name2")); + sensorEntry = cs.ds.sensors.get("switch1"); + assertNotNull(sensorEntry); + assertThat(sensorEntry.name, is("name2")); } @Test public void allAndSingleSensor() throws Exception { ContentResponse response = commonSetup.sendGet("/testuser/sensors"); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); String body = response.getContentAsString(); @@ -120,7 +125,7 @@ public void allAndSingleSensor() throws Exception { // Single light access test response = commonSetup.sendGet("/testuser/sensors/switch1"); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); body = response.getContentAsString(); assertThat(body, containsString("CLIPGenericFlag")); } diff --git a/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/UsersAndConfigTests.java b/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/UsersAndConfigTests.java index 977bde37387e2..31f0b150e0fcb 100644 --- a/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/UsersAndConfigTests.java +++ b/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/UsersAndConfigTests.java @@ -20,6 +20,7 @@ import java.util.Collections; import java.util.Dictionary; +import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jetty.client.api.ContentResponse; import org.glassfish.jersey.server.ResourceConfig; import org.junit.jupiter.api.AfterEach; @@ -29,6 +30,7 @@ import org.openhab.io.hueemulation.internal.ConfigStore; import org.openhab.io.hueemulation.internal.HueEmulationConfig; import org.openhab.io.hueemulation.internal.dto.HueUnauthorizedConfig; +import org.openhab.io.hueemulation.internal.dto.HueUserAuth; import org.openhab.io.hueemulation.internal.dto.response.HueResponse; import org.openhab.io.hueemulation.internal.dto.response.HueSuccessResponseCreateUser; import org.openhab.io.hueemulation.internal.rest.mocks.ConfigStoreWithoutMetadata; @@ -42,11 +44,12 @@ * * @author David Graeff - Initial contribution */ +@NonNullByDefault public class UsersAndConfigTests { ConfigurationAccess configurationAccess = new ConfigurationAccess(); - CommonSetup commonSetup; + private @NonNullByDefault({}) CommonSetup commonSetup; @BeforeEach public void setUp() throws IOException { @@ -94,7 +97,7 @@ public void configStoreRestartOnNoUUID() { @Test public void addUser() throws Exception { // GET should fail - assertEquals(405, commonSetup.sendGet().getStatus()); + assertThat(commonSetup.sendGet().getStatus(), is(405)); String body = "{'username':'testuser','devicetype':'app#device'}"; @@ -102,6 +105,7 @@ public void addUser() throws Exception { ContentResponse response = commonSetup.sendPost(body); assertThat(response.getStatus(), is(200)); HueResponse[] r = commonSetup.cs.gson.fromJson(response.getContentAsString(), HueResponse[].class); + assertNotNull(r); assertNotNull(r[0].error); // Post should create a user @@ -113,7 +117,9 @@ public void addUser() throws Exception { e = e.getAsJsonObject().get("success"); HueSuccessResponseCreateUser rc = commonSetup.cs.gson.fromJson(e, HueSuccessResponseCreateUser.class); assertNotNull(rc); - assertThat(commonSetup.cs.ds.config.whitelist.get(rc.username).name, is("app#device")); + HueUserAuth userAuth = commonSetup.cs.ds.config.whitelist.get(rc.username); + assertNotNull(userAuth); + assertThat(userAuth.name, is("app#device")); } @Test @@ -122,6 +128,7 @@ public void unauthorizedAccessTest() throws Exception { ContentResponse response = commonSetup.sendGet("/config"); assertThat(response.getStatus(), is(200)); HueUnauthorizedConfig config = new Gson().fromJson(response.getContentAsString(), HueUnauthorizedConfig.class); + assertNotNull(config); assertThat(config.bridgeid, is(commonSetup.cs.ds.config.bridgeid)); assertThat(config.name, is(commonSetup.cs.ds.config.name)); diff --git a/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/upnp/UpnpTests.java b/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/upnp/UpnpTests.java index 98b7b279bbe54..2b68b1c22d0f7 100644 --- a/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/upnp/UpnpTests.java +++ b/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/upnp/UpnpTests.java @@ -14,7 +14,6 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; import java.io.IOException; @@ -104,7 +103,7 @@ public static void tearDownHttp() throws Exception { @Test public void descriptionWithoutAddress() throws Exception { ContentResponse response = commonSetup.client.newRequest(descriptionPath).send(); - assertEquals(404, response.getStatus()); + assertThat(response.getStatus(), is(404)); } @Test @@ -114,7 +113,7 @@ public void descriptionWithAddress() r = subject.performAddressTest(r); subject.applyConfiguration(r); ContentResponse response = commonSetup.client.newRequest(descriptionPath).send(); - assertEquals(200, response.getStatus()); + assertThat(response.getStatus(), is(200)); String body = response.getContentAsString(); assertThat(body, is(subject.xmlDocWithAddress));