2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.persistence.dynamodb.internal;
15 import static org.junit.jupiter.api.Assertions.*;
16 import static org.junit.jupiter.api.Assumptions.*;
18 import java.math.BigDecimal;
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.List;
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.junit.jupiter.api.BeforeAll;
26 import org.junit.jupiter.api.Test;
27 import org.openhab.core.items.GroupItem;
28 import org.openhab.core.library.items.ColorItem;
29 import org.openhab.core.library.items.DimmerItem;
30 import org.openhab.core.library.items.NumberItem;
31 import org.openhab.core.library.items.RollershutterItem;
32 import org.openhab.core.library.items.StringItem;
33 import org.openhab.core.library.types.DateTimeType;
34 import org.openhab.core.library.types.DecimalType;
35 import org.openhab.core.library.types.HSBType;
36 import org.openhab.core.library.types.OnOffType;
37 import org.openhab.core.library.types.PercentType;
38 import org.openhab.core.library.types.QuantityType;
39 import org.openhab.core.library.types.StringType;
40 import org.openhab.core.library.types.UpDownType;
41 import org.openhab.core.persistence.FilterCriteria;
42 import org.openhab.core.persistence.FilterCriteria.Operator;
43 import org.openhab.core.persistence.FilterCriteria.Ordering;
44 import org.openhab.core.persistence.HistoricItem;
45 import org.openhab.core.types.State;
49 * @author Sami Salonen - Initial contribution
53 public class TestComplexItemsWithDifferentStateTypesTest extends BaseIntegrationTest {
55 private static final HSBType HSB_STATE = new HSBType(DecimalType.valueOf("20"), new PercentType(30),
57 private static final PercentType COLOR_PERCENT_STATE = new PercentType(22);
58 private static final HSBType HSB_STATE_AFTER_PERCENT = new HSBType(DecimalType.valueOf("20"), new PercentType(30),
60 private static final OnOffType COLOR_ONOFF_STATE = OnOffType.ON;
61 private static final HSBType HSB_STATE_AFTER_ONOFF = new HSBType(DecimalType.valueOf("20"), new PercentType(30),
63 public static final boolean LEGACY_MODE = false;
66 @SuppressWarnings("null")
67 public static void storeColorItemData() {
68 ColorItem item = (ColorItem) ITEMS.get("color");
70 item.setState(HSB_STATE);
75 item.setState(COLOR_PERCENT_STATE); // changes only the brightness
80 item.setState(COLOR_ONOFF_STATE); // once again, changes the brightness
84 } catch (InterruptedException e) {
90 @SuppressWarnings("null")
91 public static void storeRollershutterItemData() {
92 RollershutterItem item = (RollershutterItem) ITEMS.get("rollershutter");
94 item.setState(new PercentType(31));
98 item.setState(UpDownType.DOWN);
102 item.setState(new PercentType(32));
106 item.setState(UpDownType.UP);
110 } catch (InterruptedException e) {
116 @SuppressWarnings("null")
117 public static void storeDimmerItemData() {
118 DimmerItem item = (DimmerItem) ITEMS.get("dimmer");
121 item.setState(new PercentType(33));
125 item.setState(OnOffType.OFF);
129 item.setState(new PercentType(35));
133 item.setState(OnOffType.ON);
135 } catch (InterruptedException e) {
141 @SuppressWarnings("null")
142 public static void storeStringItemData() {
143 StringItem item = (StringItem) ITEMS.get("string");
146 item.setState(new StringType("mystring"));
150 item.setState(DateTimeType.valueOf("2021-01-17T11:18:00+02:00"));
152 } catch (InterruptedException e) {
158 @SuppressWarnings("null")
159 public static void storeTemperatureNumberItemData() {
160 NumberItem item = (NumberItem) ITEMS.get("numberTemperature");
161 assertEquals(TEMP_ITEM_UNIT, item.getUnit());
164 item.setState(new QuantityType<>("2.0 °C"));
168 item.setState(new QuantityType<>("2.0 K"));
172 item.setState(new QuantityType<>("5.1 °F"));
174 } catch (InterruptedException e) {
180 @SuppressWarnings("null")
181 public static void storeGroupTemperatureNumberItemData() {
182 GroupItem item = (GroupItem) ITEMS.get("groupNumberTemperature");
185 item.setState(new QuantityType<>("3.0 °C"));
189 item.setState(new QuantityType<>("3.0 K"));
193 item.setState(new QuantityType<>("5.1 °F"));
195 } catch (InterruptedException e) {
201 @SuppressWarnings("null")
202 public static void storeDimensionlessNumberItemData() {
203 NumberItem item = (NumberItem) ITEMS.get("numberDimensionless");
204 assertEquals(DIMENSIONLESS_ITEM_UNIT, item.getUnit());
207 item.setState(new QuantityType<>("2 %"));
211 item.setState(new QuantityType<>("3.5"));
215 item.setState(new QuantityType<>("510 ppm"));
217 } catch (InterruptedException e) {
223 @SuppressWarnings("null")
224 public static void storeDummyGroupItemData() {
225 GroupItem item = (GroupItem) ITEMS.get("groupDummy");
228 item.setState(new QuantityType<>("2 %")); // Will not write anything
230 } catch (InterruptedException e) {
236 public void testColorItem() {
237 waitForAssert(() -> {
238 assertQueryAll("color", new HSBType[] { HSB_STATE, HSB_STATE_AFTER_PERCENT, HSB_STATE_AFTER_ONOFF });
243 public void testRollershutter() {
244 // when querying, UP/DOWN are returned as PercentType
245 assertEquals(PercentType.HUNDRED, UpDownType.DOWN.as(PercentType.class));
246 assertEquals(PercentType.ZERO, UpDownType.UP.as(PercentType.class));
247 waitForAssert(() -> {
248 assertQueryAll("rollershutter",
249 new State[] { new PercentType(31), PercentType.HUNDRED, new PercentType(32), PercentType.ZERO });
254 public void testDimmer() {
255 // when querying, ON/OFF are returned as PercentType
256 assertEquals(PercentType.HUNDRED, OnOffType.ON.as(PercentType.class));
257 assertEquals(PercentType.ZERO, OnOffType.OFF.as(PercentType.class));
258 waitForAssert(() -> {
259 assertQueryAll("dimmer",
260 new State[] { new PercentType(33), PercentType.ZERO, new PercentType(35), PercentType.HUNDRED });
265 public void testString() {
266 waitForAssert(() -> {
267 assertQueryAll("string",
268 new State[] { new StringType("mystring"), new StringType("2021-01-17T09:18:00.000Z") });
273 public void testTemperatureItemNumber() {
274 waitForAssert(() -> {
275 assertQueryAll("numberTemperature",
276 new State[] { new QuantityType<>("2.0 °C"), /* 2 K = -271.15 °C */ new QuantityType<>("-271.15 °C"),
277 new QuantityType<>("-14.9444444444444444444444444444444 °C") });
278 assertQueryFilterByState("numberTemperature", Operator.GT, new QuantityType<>("-20 °C"), new State[] {
279 new QuantityType<>("2.0 °C"), new QuantityType<>("-14.9444444444444444444444444444444 °C") });
280 assertQueryFilterByState("numberTemperature", Operator.LT, new QuantityType<>("273.15 K"), new State[] {
281 new QuantityType<>("-271.15 °C"), new QuantityType<>("-14.9444444444444444444444444444444 °C") });
282 assertQueryFilterByState("numberTemperature", Operator.EQ, new QuantityType<>("5.1 °F"),
283 new State[] { new QuantityType<>("-14.9444444444444444444444444444444 °C") });
284 assertQueryFilterByState("numberTemperature", Operator.EQ, new QuantityType<>("5.1 m/s"), new State[] {});
289 public void testGroupTemperatureItemNumber() {
290 waitForAssert(() -> {
291 assertQueryAll("groupNumberTemperature",
292 new State[] { new QuantityType<>("3.0 °C"), /* 3 K = -270.15 °C */ new QuantityType<>("-270.15 °C"),
293 new QuantityType<>("-14.9444444444444444444444444444444 °C") });
294 assertQueryFilterByState("groupNumberTemperature", Operator.GT, new QuantityType<>("-20 °C"), new State[] {
295 new QuantityType<>("3.0 °C"), new QuantityType<>("-14.9444444444444444444444444444444 °C") });
296 assertQueryFilterByState("groupNumberTemperature", Operator.LT, new QuantityType<>("273.15 K"),
297 new State[] { new QuantityType<>("-270.15 °C"),
298 new QuantityType<>("-14.9444444444444444444444444444444 °C") });
299 assertQueryFilterByState("groupNumberTemperature", Operator.EQ, new QuantityType<>("5.1 °F"),
300 new State[] { new QuantityType<>("-14.9444444444444444444444444444444 °C") });
301 assertQueryFilterByState("groupNumberTemperature", Operator.EQ, new QuantityType<>("5.1 m/s"),
307 public void testGroupDummyItem() {
308 // Do not want to slow down CI runs
309 assumeFalse(isRunningInCI());
310 // only with the fast local server
311 assumeTrue(hasFakeServer());
313 // 5 seconds should be enough that any writes go through
315 } catch (InterruptedException e) {
316 fail(e.getMessage());
319 // We expect no results
320 assertQueryAll("groupDummy", new State[] {});
324 public void testDimensionlessItemNumber() {
325 waitForAssert(() -> {
326 assertQueryAll("numberDimensionless", new State[] { /* 2 % */ new QuantityType<>("0.02"),
327 new QuantityType<>("3.5"), new QuantityType<>("510").divide(new BigDecimal(1_000_000)) });
331 private void assertQueryAll(String item, State[] expectedStates) {
332 assertQueryFilterByState(item, null, null, expectedStates);
335 private void assertQueryFilterByState(String item, @Nullable Operator operator, @Nullable State state,
336 State[] expectedStates) {
337 FilterCriteria criteria = new FilterCriteria();
338 criteria.setOrdering(Ordering.ASCENDING);
339 criteria.setItemName(item);
340 if (operator != null) {
341 criteria.setOperator(operator);
344 criteria.setState(state);
346 @SuppressWarnings("null")
347 Iterable<HistoricItem> iterable = BaseIntegrationTest.service.query(criteria);
348 List<State> actualStatesList = new ArrayList<>();
349 iterable.forEach(i -> actualStatesList.add(i.getState()));
350 State[] actualStates = actualStatesList.toArray(new State[0]);
351 assertArrayEquals(expectedStates, actualStates, Arrays.toString(actualStates));