]> git.basschouten.com Git - openhab-addons.git/blob
09e4ea6f1162b12ade0377257a309518e94210ea
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.persistence.mongodb.internal;
14
15 import static org.junit.jupiter.api.Assertions.assertEquals;
16 import static org.junit.jupiter.api.Assertions.assertNotNull;
17
18 import java.util.ArrayList;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.function.BiFunction;
22
23 import org.apache.commons.lang3.tuple.Pair;
24 import org.bson.Document;
25 import org.bson.json.JsonWriterSettings;
26 import org.bson.types.Binary;
27 import org.eclipse.jdt.annotation.NonNullByDefault;
28 import org.openhab.core.library.types.DateTimeType;
29 import org.openhab.core.library.types.DecimalType;
30 import org.openhab.core.library.types.HSBType;
31 import org.openhab.core.library.types.IncreaseDecreaseType;
32 import org.openhab.core.library.types.NextPreviousType;
33 import org.openhab.core.library.types.OnOffType;
34 import org.openhab.core.library.types.OpenClosedType;
35 import org.openhab.core.library.types.PercentType;
36 import org.openhab.core.library.types.PlayPauseType;
37 import org.openhab.core.library.types.PointType;
38 import org.openhab.core.library.types.QuantityType;
39 import org.openhab.core.library.types.RawType;
40 import org.openhab.core.library.types.RewindFastforwardType;
41 import org.openhab.core.library.types.StopMoveType;
42 import org.openhab.core.library.types.StringListType;
43 import org.openhab.core.library.types.StringType;
44 import org.openhab.core.library.types.UpDownType;
45 import org.openhab.core.persistence.HistoricItem;
46
47 import ch.qos.logback.classic.Level;
48 import ch.qos.logback.classic.spi.ILoggingEvent;
49
50 /**
51  * This is a helper class for verifying various aspects of the MongoDB persistence service.
52  * It provides methods for verifying log messages, MongoDB documents, and query results.
53  * Each verification method checks if the actual value matches the expected value and throws an
54  * AssertionError if they do not match.
55  *
56  * @author RenĂ© Ulbricht - Initial contribution
57  */
58 @NonNullByDefault
59 public class VerificationHelper {
60
61     /**
62      * Verifies a log message.
63      *
64      * @param logEvent The log event to verify.
65      * @param expectedMessage The expected message of the log event.
66      * @param expectedLevel The expected level of the log event.
67      */
68     public static void verifyLogMessage(ILoggingEvent logEvent, String expectedMessage, Level expectedLevel) {
69         assertEquals(expectedMessage, logEvent.getFormattedMessage());
70         assertEquals(expectedLevel, logEvent.getLevel());
71     }
72
73     /**
74      * Verifies a document.
75      *
76      * @param document The document to verify.
77      * @param expectedItem The expected item of the document.
78      * @param expectedValue The expected value of the document.
79      */
80     public static void verifyDocument(Document document, String expectedItem, Object expectedValue) {
81         verifyDocumentWithAlias(document, expectedItem, expectedItem, expectedValue);
82     }
83
84     /**
85      * Verifies a document with an alias.
86      *
87      * @param document The document to verify.
88      * @param expectedAlias The expected alias of the document.
89      * @param expectedRealName The expected real name of the document.
90      * @param expectedValue The expected value of the document. Can be a String or a Double.
91      */
92     public static void verifyDocumentWithAlias(Document document, String expectedAlias, String expectedRealName,
93             Object expectedValue) {
94         assertEquals(expectedAlias, document.get(MongoDBFields.FIELD_ITEM));
95         assertEquals(expectedRealName, document.get(MongoDBFields.FIELD_REALNAME));
96
97         // Use the map to handle the expected value
98         BiFunction<Object, Document, Pair<Object, Object>> handler = HandleTypes.get(expectedValue.getClass());
99         if (handler == null) {
100             throw new IllegalArgumentException("Unsupported type: " + expectedValue.getClass());
101         }
102         Pair<Object, Object> values = handler.apply(expectedValue, document);
103
104         JsonWriterSettings jsonWriterSettings = JsonWriterSettings.builder().indent(true).build();
105         assertEquals(values.getLeft(), values.getRight(),
106                 "Document: (" + expectedValue.getClass().getSimpleName() + ") " + document.toJson(jsonWriterSettings));
107
108         assertNotNull(document.get("_id"));
109         assertNotNull(document.get("timestamp"));
110     }
111
112     /**
113      * Verifies the result of a query.
114      *
115      * @param result The result of the query.
116      * @param startState The state of the first item in the result.
117      * @param increment The increment for the expected state.
118      */
119     public static void verifyQueryResult(Iterable<HistoricItem> result, int startState, int increment, int totalSize) {
120         List<HistoricItem> resultList = new ArrayList<>();
121         result.forEach(resultList::add);
122
123         assertEquals(totalSize, resultList.size());
124
125         int expectedState = startState;
126         for (HistoricItem item : resultList) {
127             assertEquals(expectedState, ((DecimalType) item.getState()).intValue());
128             expectedState += increment;
129         }
130     }
131
132     public static void verifyQueryResult(Iterable<HistoricItem> result, Object expectedState) {
133         List<HistoricItem> resultList = new ArrayList<>();
134         result.forEach(resultList::add);
135
136         assertEquals(1, resultList.size());
137
138         assertEquals(expectedState, resultList.get(0).getState());
139     }
140
141     // Define a map from types to functions that handle those types
142     private static final Map<Class<?>, BiFunction<Object, Document, Pair<Object, Object>>> HandleTypes = Map.ofEntries(
143             Map.entry(Double.class, VerificationHelper::handleGeneric),
144             Map.entry(String.class, VerificationHelper::handleGeneric),
145             Map.entry(HSBType.class, VerificationHelper::handleToString),
146             Map.entry(DecimalType.class, VerificationHelper::handleDecimalType),
147             Map.entry(DateTimeType.class, VerificationHelper::handleDateTimeType),
148             Map.entry(IncreaseDecreaseType.class, VerificationHelper::handleToString),
149             Map.entry(RewindFastforwardType.class, VerificationHelper::handleToString),
150             Map.entry(NextPreviousType.class, VerificationHelper::handleToString),
151             Map.entry(OnOffType.class, VerificationHelper::handleToString),
152             Map.entry(OpenClosedType.class, VerificationHelper::handleToString),
153             Map.entry(PercentType.class, VerificationHelper::handlePercentType),
154             Map.entry(PlayPauseType.class, VerificationHelper::handleToString),
155             Map.entry(PointType.class, VerificationHelper::handleToString),
156             Map.entry(StopMoveType.class, VerificationHelper::handleToString),
157             Map.entry(StringListType.class, VerificationHelper::handleToString),
158             Map.entry(StringType.class, VerificationHelper::handleGeneric),
159             Map.entry(UpDownType.class, VerificationHelper::handleToString),
160             Map.entry(QuantityType.class, VerificationHelper::handleQuantityType),
161             Map.entry(RawType.class, VerificationHelper::handleRawType));
162
163     private static Pair<Object, Object> handleGeneric(Object ev, Document doc) {
164         Object value = doc.get(MongoDBFields.FIELD_VALUE);
165         return Pair.of(ev, value != null ? value : new Object());
166     }
167
168     private static Pair<Object, Object> handleToString(Object ev, Document doc) {
169         Object value = doc.get(MongoDBFields.FIELD_VALUE);
170         return Pair.of(ev.toString(), value != null ? value : new Object());
171     }
172
173     private static Pair<Object, Object> handleDecimalType(Object ev, Document doc) {
174         Double value = doc.getDouble(MongoDBFields.FIELD_VALUE);
175         return Pair.of(((DecimalType) ev).doubleValue(), value != null ? value : new Object());
176     }
177
178     private static Pair<Object, Object> handleDateTimeType(Object ev, Document doc) {
179         String value = doc.getString(MongoDBFields.FIELD_VALUE);
180         return Pair.of(((DateTimeType) ev).getZonedDateTime().toString(), value != null ? value : new Object());
181     }
182
183     private static Pair<Object, Object> handlePercentType(Object ev, Document doc) {
184         Integer value = doc.getInteger(MongoDBFields.FIELD_VALUE);
185         return Pair.of(((PercentType) ev).intValue(), value != null ? value : new Object());
186     }
187
188     private static Pair<Object, Object> handleQuantityType(Object ev, Document doc) {
189         Double value = doc.getDouble(MongoDBFields.FIELD_VALUE);
190         String unit = doc.getString(MongoDBFields.FIELD_UNIT);
191         if (value != null && unit != null) {
192             QuantityType<?> quantityType = (QuantityType<?>) ev;
193             return Pair.of(quantityType.doubleValue() + "--" + quantityType.getUnit(), value + "--" + unit);
194         }
195         return Pair.of(new Object(), new Object());
196     }
197
198     private static Pair<Object, Object> handleRawType(Object ev, Document doc) {
199         RawType rawType = (RawType) ev;
200         Document expectedDoc = new Document();
201         expectedDoc.put(MongoDBFields.FIELD_VALUE_TYPE, rawType.getMimeType());
202         expectedDoc.put(MongoDBFields.FIELD_VALUE_DATA, new Binary(rawType.getBytes()));
203         Object value = doc.get(MongoDBFields.FIELD_VALUE);
204         return Pair.of(expectedDoc, value != null ? value : new Object());
205     }
206 }