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.assumeTrue;
18 import java.time.ZoneId;
19 import java.time.ZonedDateTime;
20 import java.util.Iterator;
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.junit.jupiter.api.Test;
25 import org.openhab.core.persistence.FilterCriteria;
26 import org.openhab.core.persistence.FilterCriteria.Operator;
27 import org.openhab.core.persistence.FilterCriteria.Ordering;
28 import org.openhab.core.persistence.HistoricItem;
29 import org.openhab.core.types.State;
32 * This is abstract class helping with integration testing the persistence service. Different kind of queries are tested
33 * against actual dynamo db database.
36 * Inheritor of this base class needs to store two states of one item in a static method annotated with @BeforeAll.
39 * class should update the private static fields
40 * beforeStore (date before storing anything), afterStore1 (after storing first item, but before storing second item),
41 * afterStore2 (after storing second item). The item name must correspond to getItemName. The first state needs to be
42 * smaller than the second state.
44 * To have more comprehensive tests, the inheritor class can define getQueryItemStateBetween to provide a value between
45 * the two states. Null can be used to omit the additional tests.
48 * See DimmerItemIntegrationTest for example how to use this base class.
50 * @author Sami Salonen - Initial contribution
54 public abstract class AbstractTwoItemIntegrationTest extends BaseIntegrationTest {
56 protected static ZonedDateTime beforeStore = ZonedDateTime.of(2100, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault());
57 protected static ZonedDateTime afterStore1 = ZonedDateTime.of(1900, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault());
58 protected static ZonedDateTime afterStore2 = ZonedDateTime.of(1900, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault());
60 protected abstract String getItemName();
63 * State of the time item stored first, should be smaller than the second value
67 protected abstract State getFirstItemState();
70 * State of the time item stored second, should be larger than the first value
74 protected abstract State getSecondItemState();
77 * State that is between the first and second. Use null to omit extended tests using this value.
81 protected abstract @Nullable State getQueryItemStateBetween();
83 protected void assertStateEquals(State expected, State actual) {
84 assertEquals(expected, actual);
88 * Asserts that iterable contains correct items and nothing else
91 protected void assertIterableContainsItems(Iterable<HistoricItem> iterable, boolean ascending) {
92 Iterator<HistoricItem> iterator = iterable.iterator();
93 assertTrue(iterator.hasNext());
94 HistoricItem actual1 = iterator.next();
95 assertTrue(iterator.hasNext());
96 HistoricItem actual2 = iterator.next();
97 assertFalse(iterator.hasNext());
99 for (HistoricItem actual : new HistoricItem[] { actual1, actual2 }) {
100 assertEquals(getItemName(), actual.getName());
102 HistoricItem storedFirst;
103 HistoricItem storedSecond;
105 storedFirst = actual1;
106 storedSecond = actual2;
108 storedFirst = actual2;
109 storedSecond = actual1;
112 assertStateEquals(getFirstItemState(), storedFirst.getState());
113 assertTrue(storedFirst.getTimestamp().toInstant().isBefore(afterStore1.toInstant()));
114 assertTrue(storedFirst.getTimestamp().toInstant().isAfter(beforeStore.toInstant()));
116 assertStateEquals(getSecondItemState(), storedSecond.getState());
117 assertTrue(storedSecond.getTimestamp().toInstant().isBefore(afterStore2.toInstant()));
118 assertTrue(storedSecond.getTimestamp().toInstant().isAfter(afterStore1.toInstant()));
122 public void testQueryUsingName() {
123 waitForAssert(() -> {
124 FilterCriteria criteria = new FilterCriteria();
125 criteria.setOrdering(Ordering.ASCENDING);
126 criteria.setItemName(getItemName());
127 @SuppressWarnings("null")
128 Iterable<HistoricItem> iterable = BaseIntegrationTest.service.query(criteria);
129 assertIterableContainsItems(iterable, true);
134 public void testQueryUsingNameAndStart() {
135 waitForAssert(() -> {
136 FilterCriteria criteria = new FilterCriteria();
137 criteria.setOrdering(Ordering.ASCENDING);
138 criteria.setItemName(getItemName());
139 criteria.setBeginDate(beforeStore);
140 @SuppressWarnings("null")
141 Iterable<HistoricItem> iterable = BaseIntegrationTest.service.query(criteria);
142 assertIterableContainsItems(iterable, true);
147 public void testQueryUsingNameAndStartNoMatch() {
148 waitForAssert(() -> {
150 FilterCriteria criteria = new FilterCriteria();
151 criteria.setItemName(getItemName());
152 criteria.setBeginDate(afterStore2);
153 @SuppressWarnings("null")
154 Iterable<HistoricItem> iterable = BaseIntegrationTest.service.query(criteria);
155 assertFalse(iterable.iterator().hasNext());
160 public void testQueryUsingNameAndEnd() {
161 waitForAssert(() -> {
162 FilterCriteria criteria = new FilterCriteria();
163 criteria.setOrdering(Ordering.ASCENDING);
164 criteria.setItemName(getItemName());
165 criteria.setEndDate(afterStore2);
166 @SuppressWarnings("null")
167 Iterable<HistoricItem> iterable = BaseIntegrationTest.service.query(criteria);
168 assertIterableContainsItems(iterable, true);
173 public void testQueryUsingNameAndEndNoMatch() {
174 waitForAssert(() -> {
175 FilterCriteria criteria = new FilterCriteria();
176 criteria.setItemName(getItemName());
177 criteria.setEndDate(beforeStore);
178 @SuppressWarnings("null")
179 Iterable<HistoricItem> iterable = BaseIntegrationTest.service.query(criteria);
180 assertFalse(iterable.iterator().hasNext());
185 public void testQueryUsingNameAndStartAndEnd() {
186 waitForAssert(() -> {
187 FilterCriteria criteria = new FilterCriteria();
188 criteria.setOrdering(Ordering.ASCENDING);
189 criteria.setItemName(getItemName());
190 criteria.setBeginDate(beforeStore);
191 criteria.setEndDate(afterStore2);
192 @SuppressWarnings("null")
193 Iterable<HistoricItem> iterable = BaseIntegrationTest.service.query(criteria);
194 assertIterableContainsItems(iterable, true);
199 public void testQueryUsingNameAndStartAndEndDesc() {
200 waitForAssert(() -> {
201 FilterCriteria criteria = new FilterCriteria();
202 criteria.setOrdering(Ordering.DESCENDING);
203 criteria.setItemName(getItemName());
204 criteria.setBeginDate(beforeStore);
205 criteria.setEndDate(afterStore2);
206 @SuppressWarnings("null")
207 Iterable<HistoricItem> iterable = BaseIntegrationTest.service.query(criteria);
208 assertIterableContainsItems(iterable, false);
213 public void testQueryUsingNameAndStartAndEndWithNEQOperator() {
214 waitForAssert(() -> {
215 FilterCriteria criteria = new FilterCriteria();
216 criteria.setOperator(Operator.NEQ);
217 criteria.setState(getSecondItemState());
218 criteria.setItemName(getItemName());
219 criteria.setBeginDate(beforeStore);
220 criteria.setEndDate(afterStore2);
221 @SuppressWarnings("null")
222 Iterable<HistoricItem> iterable = BaseIntegrationTest.service.query(criteria);
223 Iterator<HistoricItem> iterator = iterable.iterator();
224 assertTrue(iterator.hasNext());
225 HistoricItem actual1 = iterator.next();
226 assertFalse(iterator.hasNext());
227 assertStateEquals(getFirstItemState(), actual1.getState());
228 assertTrue(actual1.getTimestamp().toInstant().isBefore(afterStore1.toInstant()));
229 assertTrue(actual1.getTimestamp().toInstant().isAfter(beforeStore.toInstant()));
234 public void testQueryUsingNameAndStartAndEndWithEQOperator() {
235 waitForAssert(() -> {
236 FilterCriteria criteria = new FilterCriteria();
237 criteria.setOperator(Operator.EQ);
238 criteria.setState(getFirstItemState());
239 criteria.setItemName(getItemName());
240 criteria.setBeginDate(beforeStore);
241 criteria.setEndDate(afterStore2);
242 @SuppressWarnings("null")
243 Iterable<HistoricItem> iterable = BaseIntegrationTest.service.query(criteria);
244 Iterator<HistoricItem> iterator = iterable.iterator();
245 assertTrue(iterator.hasNext());
246 HistoricItem actual1 = iterator.next();
247 assertFalse(iterator.hasNext());
248 assertStateEquals(getFirstItemState(), actual1.getState());
249 assertTrue(actual1.getTimestamp().toInstant().isBefore(afterStore1.toInstant()));
250 assertTrue(actual1.getTimestamp().toInstant().isAfter(beforeStore.toInstant()));
255 public void testQueryUsingNameAndStartAndEndWithLTOperator() {
256 waitForAssert(() -> {
257 FilterCriteria criteria = new FilterCriteria();
258 criteria.setOperator(Operator.LT);
259 criteria.setState(getSecondItemState());
260 criteria.setItemName(getItemName());
261 criteria.setBeginDate(beforeStore);
262 criteria.setEndDate(afterStore2);
263 @SuppressWarnings("null")
264 Iterable<HistoricItem> iterable = BaseIntegrationTest.service.query(criteria);
265 Iterator<HistoricItem> iterator = iterable.iterator();
266 assertTrue(iterator.hasNext());
267 HistoricItem actual1 = iterator.next();
268 assertFalse(iterator.hasNext());
269 assertStateEquals(getFirstItemState(), actual1.getState());
270 assertTrue(actual1.getTimestamp().toInstant().isBefore(afterStore1.toInstant()));
271 assertTrue(actual1.getTimestamp().toInstant().isAfter(beforeStore.toInstant()));
276 public void testQueryUsingNameAndStartAndEndWithLTOperatorNoMatch() {
277 waitForAssert(() -> {
278 FilterCriteria criteria = new FilterCriteria();
279 criteria.setOperator(Operator.LT);
280 criteria.setState(getFirstItemState());
281 criteria.setItemName(getItemName());
282 criteria.setBeginDate(beforeStore);
283 criteria.setEndDate(afterStore2);
284 @SuppressWarnings("null")
285 Iterable<HistoricItem> iterable = BaseIntegrationTest.service.query(criteria);
286 Iterator<HistoricItem> iterator = iterable.iterator();
287 assertFalse(iterator.hasNext());
292 public void testQueryUsingNameAndStartAndEndWithLTEOperator() {
293 waitForAssert(() -> {
294 FilterCriteria criteria = new FilterCriteria();
295 criteria.setOperator(Operator.LTE);
296 criteria.setState(getFirstItemState());
297 criteria.setItemName(getItemName());
298 criteria.setBeginDate(beforeStore);
299 criteria.setEndDate(afterStore2);
300 @SuppressWarnings("null")
301 Iterable<HistoricItem> iterable = BaseIntegrationTest.service.query(criteria);
302 Iterator<HistoricItem> iterator = iterable.iterator();
303 assertTrue(iterator.hasNext());
304 HistoricItem actual1 = iterator.next();
305 assertFalse(iterator.hasNext());
306 assertStateEquals(getFirstItemState(), actual1.getState());
307 assertTrue(actual1.getTimestamp().toInstant().isBefore(afterStore1.toInstant()));
308 assertTrue(actual1.getTimestamp().toInstant().isAfter(beforeStore.toInstant()));
313 public void testQueryUsingNameAndStartAndEndWithGTOperator() {
314 waitForAssert(() -> {
315 // Skip for subclasses which have null "state between"
316 assumeTrue(getQueryItemStateBetween() != null);
318 FilterCriteria criteria = new FilterCriteria();
319 criteria.setOperator(Operator.GT);
320 State filterState = getQueryItemStateBetween();
321 if (filterState != null) {
322 criteria.setState(filterState);
324 criteria.setItemName(getItemName());
325 criteria.setBeginDate(beforeStore);
326 criteria.setEndDate(afterStore2);
327 @SuppressWarnings("null")
328 Iterable<HistoricItem> iterable = BaseIntegrationTest.service.query(criteria);
329 Iterator<HistoricItem> iterator = iterable.iterator();
330 assertTrue(iterator.hasNext());
331 HistoricItem actual1 = iterator.next();
332 assertFalse(iterator.hasNext());
333 assertStateEquals(getSecondItemState(), actual1.getState());
334 assertTrue(actual1.getTimestamp().toInstant().isBefore(afterStore2.toInstant()));
335 assertTrue(actual1.getTimestamp().toInstant().isAfter(afterStore1.toInstant()));
340 public void testQueryUsingNameAndStartAndEndWithGTOperatorNoMatch() {
341 waitForAssert(() -> {
342 FilterCriteria criteria = new FilterCriteria();
343 criteria.setOperator(Operator.GT);
344 criteria.setState(getSecondItemState());
345 criteria.setItemName(getItemName());
346 criteria.setBeginDate(beforeStore);
347 criteria.setEndDate(afterStore2);
348 @SuppressWarnings("null")
349 Iterable<HistoricItem> iterable = BaseIntegrationTest.service.query(criteria);
350 Iterator<HistoricItem> iterator = iterable.iterator();
351 assertFalse(iterator.hasNext());
356 public void testQueryUsingNameAndStartAndEndWithGTEOperator() {
357 waitForAssert(() -> {
358 FilterCriteria criteria = new FilterCriteria();
359 criteria.setOperator(Operator.GTE);
360 criteria.setState(getSecondItemState());
361 criteria.setItemName(getItemName());
362 criteria.setBeginDate(beforeStore);
363 criteria.setEndDate(afterStore2);
364 @SuppressWarnings("null")
365 Iterable<HistoricItem> iterable = BaseIntegrationTest.service.query(criteria);
366 Iterator<HistoricItem> iterator = iterable.iterator();
367 assertTrue(iterator.hasNext());
368 HistoricItem actual1 = iterator.next();
369 assertFalse(iterator.hasNext());
370 assertStateEquals(getSecondItemState(), actual1.getState());
371 assertTrue(actual1.getTimestamp().toInstant().isBefore(afterStore2.toInstant()));
372 assertTrue(actual1.getTimestamp().toInstant().isAfter(afterStore1.toInstant()));
377 public void testQueryUsingNameAndStartAndEndFirst() {
378 waitForAssert(() -> {
379 FilterCriteria criteria = new FilterCriteria();
380 criteria.setOrdering(Ordering.ASCENDING);
381 criteria.setItemName(getItemName());
382 criteria.setBeginDate(beforeStore);
383 criteria.setEndDate(afterStore1);
384 @SuppressWarnings("null")
385 Iterable<HistoricItem> iterable = BaseIntegrationTest.service.query(criteria);
387 Iterator<HistoricItem> iterator = iterable.iterator();
388 assertTrue(iterator.hasNext());
389 HistoricItem actual1 = iterator.next();
390 assertFalse(iterator.hasNext());
391 assertStateEquals(getFirstItemState(), actual1.getState());
392 assertTrue(actual1.getTimestamp().toInstant().isBefore(afterStore1.toInstant()));
393 assertTrue(actual1.getTimestamp().toInstant().isAfter(beforeStore.toInstant()));
398 public void testQueryUsingNameAndStartAndEndNoMatch() {
399 waitForAssert(() -> {
400 FilterCriteria criteria = new FilterCriteria();
401 criteria.setItemName(getItemName());
402 criteria.setBeginDate(beforeStore);
403 criteria.setEndDate(beforeStore); // sic
404 @SuppressWarnings("null")
405 Iterable<HistoricItem> iterable = BaseIntegrationTest.service.query(criteria);
406 assertFalse(iterable.iterator().hasNext());