2 * Copyright (c) 2010-2024 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.mongodb.internal;
15 import static org.junit.jupiter.api.Assertions.assertEquals;
16 import static org.junit.jupiter.api.Assertions.assertTrue;
18 import java.text.DateFormat;
19 import java.time.LocalDate;
20 import java.time.ZoneId;
21 import java.time.ZonedDateTime;
22 import java.time.temporal.ChronoUnit;
23 import java.util.ArrayList;
24 import java.util.Date;
25 import java.util.List;
28 import java.util.stream.Collectors;
30 import org.bson.Document;
31 import org.bson.types.ObjectId;
32 import org.junit.jupiter.api.Disabled;
33 import org.junit.jupiter.api.Test;
34 import org.junit.jupiter.params.ParameterizedTest;
35 import org.junit.jupiter.params.provider.MethodSource;
36 import org.mockito.Mockito;
37 import org.openhab.core.items.GenericItem;
38 import org.openhab.core.items.ItemNotFoundException;
39 import org.openhab.core.library.items.ColorItem;
40 import org.openhab.core.library.items.DateTimeItem;
41 import org.openhab.core.library.items.ImageItem;
42 import org.openhab.core.library.items.NumberItem;
43 import org.openhab.core.library.items.StringItem;
44 import org.openhab.core.library.types.DateTimeType;
45 import org.openhab.core.library.types.DecimalType;
46 import org.openhab.core.library.types.HSBType;
47 import org.openhab.core.library.types.QuantityType;
48 import org.openhab.core.library.types.RawType;
49 import org.openhab.core.persistence.FilterCriteria;
50 import org.openhab.core.persistence.HistoricItem;
51 import org.osgi.framework.BundleContext;
53 import com.mongodb.client.MongoCollection;
54 import com.mongodb.client.MongoDatabase;
56 import ch.qos.logback.classic.Level;
57 import ch.qos.logback.classic.spi.ILoggingEvent;
58 import ch.qos.logback.core.read.ListAppender;
59 import de.bwaldvogel.mongo.backend.memory.MemoryBackend;
62 * This is the implementation of the test for MongoDB {@link PersistenceService}.
64 * @author René Ulbricht - Initial contribution
66 @Disabled("Fails on CPUs without AVX support, see: https://github.com/openhab/openhab-addons/issues/17046")
67 public class MongoDBPersistenceServiceTest {
70 * Tests the activate method of MongoDBPersistenceService.
72 * This test checks if the activate method correctly logs the MongoDB URL, database, and collection.
73 * It uses different database backends provided by the provideDatabaseBackends method.
75 * @param dbContainer The container running the MongoDB instance.
78 @MethodSource("org.openhab.persistence.mongodb.internal.DataCreationHelper#provideDatabaseBackends")
79 public void testActivate(DatabaseTestContainer dbContainer) {
82 SetupResult setupResult = DataCreationHelper.setupMongoDB("testCollection", dbContainer);
85 ListAppender<ILoggingEvent> listAppender = DataCreationHelper.setupLogger(MongoDBPersistenceService.class,
89 setupResult.service.activate(setupResult.bundleContext, setupResult.config);
92 List<ILoggingEvent> logsList = listAppender.list;
93 VerificationHelper.verifyLogMessage(logsList.get(0), "MongoDB URL " + dbContainer.getConnectionString(),
95 VerificationHelper.verifyLogMessage(logsList.get(1), "MongoDB database " + setupResult.dbname, Level.DEBUG);
96 VerificationHelper.verifyLogMessage(logsList.get(2), "MongoDB collection testCollection", Level.DEBUG);
103 * Tests the deactivate method of MongoDBPersistenceService.
105 * This test checks if the deactivate method correctly logs a message when the MongoDB persistence bundle is
107 * It uses different database backends provided by the provideDatabaseBackends method.
109 * @param dbContainer The container running the MongoDB instance.
112 @MethodSource("org.openhab.persistence.mongodb.internal.DataCreationHelper#provideDatabaseBackends")
113 public void testDeactivate(DatabaseTestContainer dbContainer) {
116 SetupResult setupResult = DataCreationHelper.setupMongoDB("testCollection", dbContainer);
118 setupResult.service.activate(setupResult.bundleContext, setupResult.config);
121 ListAppender<ILoggingEvent> listAppender = DataCreationHelper.setupLogger(MongoDBPersistenceService.class,
125 setupResult.service.deactivate(1);
128 List<ILoggingEvent> logsList = listAppender.list;
129 VerificationHelper.verifyLogMessage(logsList.get(0),
130 "MongoDB persistence bundle stopping. Disconnecting from database.", Level.DEBUG);
137 * Tests the getId method of MongoDBPersistenceService.
139 * This test checks if the getId method correctly returns the ID of the MongoDBPersistenceService, which should be
143 public void testGetId() {
145 DatabaseTestContainer dbContainer = new DatabaseTestContainer(new MemoryBackend());
147 SetupResult setupResult = DataCreationHelper.setupMongoDB(null, dbContainer);
148 MongoDBPersistenceService service = setupResult.service;
151 String id = service.getId();
154 assertEquals("mongodb", id);
161 * Tests the getLabel method of MongoDBPersistenceService.
163 * This test checks if the getLabel method correctly returns the label of the MongoDBPersistenceService, which
164 * should be "MongoDB".
167 public void testGetLabel() {
169 DatabaseTestContainer dbContainer = new DatabaseTestContainer(new MemoryBackend());
171 SetupResult setupResult = DataCreationHelper.setupMongoDB(null, dbContainer);
172 MongoDBPersistenceService service = setupResult.service;
175 String label = service.getLabel(null);
178 assertEquals("MongoDB", label);
185 * Tests the store method of MongoDBPersistenceService with a NumberItem.
187 * This test checks if the store method correctly stores a NumberItem in the MongoDB database.
188 * It uses different database backends provided by the provideDatabaseBackends method.
190 * @param dbContainer The container running the MongoDB instance.
193 @MethodSource("org.openhab.persistence.mongodb.internal.DataCreationHelper#provideDatabaseBackends")
194 public void testStoreNumber(DatabaseTestContainer dbContainer) {
197 SetupResult setupResult = DataCreationHelper.setupMongoDB("testCollection", dbContainer);
198 MongoDBPersistenceService service = setupResult.service;
199 MongoDatabase database = setupResult.database;
201 service.activate(setupResult.bundleContext, setupResult.config);
203 NumberItem item = DataCreationHelper.createNumberItem("TestItem", 10.1);
206 service.store(item, null);
209 MongoCollection<Document> collection = database.getCollection("testCollection");
210 List<Document> documents = (ArrayList<Document>) collection.find().into(new ArrayList<>());
212 assertEquals(1, documents.size()); // Assert that there is only one document
214 Document insertedDocument = documents.get(0); // Get the first (and only) document
216 VerificationHelper.verifyDocument(insertedDocument, "TestItem", 10.1);
223 * Tests the store method of MongoDBPersistenceService with a StringItem.
225 * This test checks if the store method correctly stores a StringItem in the MongoDB database.
226 * It uses different database backends provided by the provideDatabaseBackends method.
228 * @param dbContainer The container running the MongoDB instance.
231 @MethodSource("org.openhab.persistence.mongodb.internal.DataCreationHelper#provideDatabaseBackends")
232 public void testStoreString(DatabaseTestContainer dbContainer) {
235 SetupResult setupResult = DataCreationHelper.setupMongoDB("testCollection", dbContainer);
236 MongoDBPersistenceService service = setupResult.service;
237 MongoDatabase database = setupResult.database;
239 service.activate(setupResult.bundleContext, setupResult.config);
241 StringItem item = DataCreationHelper.createStringItem("TestItem", "TestValue");
244 service.store(item, null);
247 MongoCollection<Document> collection = database.getCollection("testCollection");
248 List<Document> documents = (ArrayList<Document>) collection.find().into(new ArrayList<>());
250 assertEquals(1, documents.size()); // Assert that there is only one document
252 Document insertedDocument = documents.get(0); // Get the first (and only) document
254 VerificationHelper.verifyDocument(insertedDocument, "TestItem", "TestValue");
261 * Tests the store method of MongoDBPersistenceService with multiple items in a single collection.
263 * This test checks if the store method correctly stores multiple items in the same MongoDB collection.
264 * It uses different database backends provided by the provideDatabaseBackends method.
266 * @param dbContainer The container running the MongoDB instance.
269 @MethodSource("org.openhab.persistence.mongodb.internal.DataCreationHelper#provideDatabaseBackends")
270 public void testStoreSingleCollection(DatabaseTestContainer dbContainer) {
273 SetupResult setupResult = DataCreationHelper.setupMongoDB("testCollection", dbContainer);
274 MongoDBPersistenceService service = setupResult.service;
275 MongoDatabase database = setupResult.database;
277 service.activate(setupResult.bundleContext, setupResult.config);
279 StringItem strItem1 = DataCreationHelper.createStringItem("TestItem", "TestValue");
280 StringItem strItem2 = DataCreationHelper.createStringItem("SecondTestItem", "SecondTestValue");
283 service.store(strItem1, null);
284 service.store(strItem2, null);
287 MongoCollection<Document> collection = database.getCollection("testCollection");
288 List<Document> documents = (ArrayList<Document>) collection.find().into(new ArrayList<>());
290 assertEquals(2, documents.size()); // Assert that there are two documents
292 Document insertedDocument1 = documents.get(0); // Get the first document
293 VerificationHelper.verifyDocument(insertedDocument1, "TestItem", "TestValue");
295 Document insertedDocument2 = documents.get(1); // Get the second document
296 VerificationHelper.verifyDocument(insertedDocument2, "SecondTestItem", "SecondTestValue");
303 * Tests the store method of MongoDBPersistenceService with multiple items.
305 * This test checks if the store method correctly stores multiple items in the same MongoDB collection.
306 * It uses different database backends provided by the provideDatabaseBackends method.
308 * @param dbContainer The container running the MongoDB instance.
311 @MethodSource("org.openhab.persistence.mongodb.internal.DataCreationHelper#provideDatabaseBackends")
312 public void testStoreMultipleItemsSingleCollection(DatabaseTestContainer dbContainer) {
315 SetupResult setupResult = DataCreationHelper.setupMongoDB("testCollection", dbContainer);
316 MongoDBPersistenceService service = setupResult.service;
317 MongoDatabase database = setupResult.database;
319 service.activate(setupResult.bundleContext, setupResult.config);
321 StringItem strItem1 = DataCreationHelper.createStringItem("TestItem1", "TestValue1");
322 StringItem strItem2 = DataCreationHelper.createStringItem("TestItem2", "TestValue2");
325 service.store(strItem1, null);
326 service.store(strItem2, null);
329 MongoCollection<Document> collection = database.getCollection("testCollection");
330 List<Document> documents = (ArrayList<Document>) collection.find().into(new ArrayList<>());
332 assertEquals(2, documents.size()); // Assert that there are two documents
334 Document insertedDocument1 = documents.get(0); // Get the first document
335 VerificationHelper.verifyDocument(insertedDocument1, "TestItem1", "TestValue1");
337 Document insertedDocument2 = documents.get(1); // Get the second document
338 VerificationHelper.verifyDocument(insertedDocument2, "TestItem2", "TestValue2");
345 * Tests the store method of MongoDBPersistenceService with a StringItem and an alias.
347 * This test checks if the store method correctly stores a StringItem with an alias in the MongoDB database.
348 * It uses different database backends provided by the provideDatabaseBackends method.
350 * @param dbContainer The container running the MongoDB instance.
353 @MethodSource("org.openhab.persistence.mongodb.internal.DataCreationHelper#provideDatabaseBackends")
354 public void testStoreStringWithAlias(DatabaseTestContainer dbContainer) {
357 SetupResult setupResult = DataCreationHelper.setupMongoDB("testCollection", dbContainer);
358 MongoDBPersistenceService service = setupResult.service;
359 MongoDatabase database = setupResult.database;
361 service.activate(setupResult.bundleContext, setupResult.config);
363 StringItem item = DataCreationHelper.createStringItem("TestItem", "TestValue");
366 service.store(item, "AliasName");
369 MongoCollection<Document> collection = database.getCollection("testCollection");
370 List<Document> documents = (ArrayList<Document>) collection.find().into(new ArrayList<>());
372 assertEquals(1, documents.size()); // Assert that there is only one document
374 Document insertedDocument = documents.get(0); // Get the first (and only) document
376 VerificationHelper.verifyDocumentWithAlias(insertedDocument, "AliasName", "TestItem", "TestValue");
383 * Tests the query method of MongoDBPersistenceService with NumberItems in a single collection.
385 * This test checks if the query method correctly retrieves NumberItems from a single MongoDB collection.
386 * It uses different database backends provided by the provideDatabaseBackends method.
388 * @param dbContainer The container running the MongoDB instance.
391 @MethodSource("org.openhab.persistence.mongodb.internal.DataCreationHelper#provideDatabaseBackends")
392 public void testQueryNumberItemsInOneCollection(DatabaseTestContainer dbContainer) {
395 SetupResult setupResult = DataCreationHelper.setupMongoDB("testCollection", dbContainer);
396 MongoDBPersistenceService service = setupResult.service;
398 // Add items to the ItemRegistry
399 NumberItem itemReg1 = DataCreationHelper.createNumberItem("TestItem", 0);
400 NumberItem itemReg2 = DataCreationHelper.createNumberItem("TestItem2", 0);
402 Mockito.when(setupResult.itemRegistry.getItem("TestItem")).thenReturn(itemReg1);
403 Mockito.when(setupResult.itemRegistry.getItem("TestItem2")).thenReturn(itemReg2);
404 } catch (ItemNotFoundException e) {
407 service.activate(setupResult.bundleContext, setupResult.config);
410 for (int i = 0; i < 10; i++) {
411 NumberItem item1 = DataCreationHelper.createNumberItem("TestItem", i);
412 NumberItem item2 = DataCreationHelper.createNumberItem("TestItem2", i * 2);
413 service.store(item1, null);
414 service.store(item2, null);
418 FilterCriteria filter1 = DataCreationHelper.createFilterCriteria("TestItem");
419 Iterable<HistoricItem> result1 = service.query(filter1);
421 FilterCriteria filter2 = DataCreationHelper.createFilterCriteria("TestItem2");
422 Iterable<HistoricItem> result2 = service.query(filter2);
425 VerificationHelper.verifyQueryResult(result1, 0, 1, 10);
426 VerificationHelper.verifyQueryResult(result2, 0, 2, 10);
433 * Tests the query method of MongoDBPersistenceService with NumberItems in multiple collections.
435 * This test checks if the query method correctly retrieves NumberItems from multiple MongoDB collections.
436 * It uses different database backends provided by the provideDatabaseBackends method.
438 * @param dbContainer The container running the MongoDB instance.
441 @MethodSource("org.openhab.persistence.mongodb.internal.DataCreationHelper#provideDatabaseBackends")
442 public void testQueryNumberItemsInMultipleCollections(DatabaseTestContainer dbContainer) {
445 SetupResult setupResult = DataCreationHelper.setupMongoDB(null, dbContainer);
446 MongoDBPersistenceService service = setupResult.service;
447 BundleContext bundleContext = setupResult.bundleContext;
448 Map<String, Object> config = setupResult.config;
451 Mockito.when(setupResult.itemRegistry.getItem("TestItem"))
452 .thenReturn(DataCreationHelper.createNumberItem("TestItem", 0));
453 Mockito.when(setupResult.itemRegistry.getItem("TestItem2"))
454 .thenReturn(DataCreationHelper.createNumberItem("TestItem2", 0));
455 } catch (ItemNotFoundException e) {
458 service.activate(bundleContext, config);
461 for (int i = 0; i < 10; i++) {
462 NumberItem item1 = DataCreationHelper.createNumberItem("TestItem", i);
463 NumberItem item2 = DataCreationHelper.createNumberItem("TestItem2", i * 2);
464 service.store(item1, null);
465 service.store(item2, null);
469 FilterCriteria filter1 = DataCreationHelper.createFilterCriteria("TestItem");
470 Iterable<HistoricItem> result1 = service.query(filter1);
472 FilterCriteria filter2 = DataCreationHelper.createFilterCriteria("TestItem2");
473 Iterable<HistoricItem> result2 = service.query(filter2);
476 VerificationHelper.verifyQueryResult(result1, 0, 1, 10);
477 VerificationHelper.verifyQueryResult(result2, 0, 2, 10);
484 * Tests the query method of MongoDBPersistenceService with NumberItems in a single collection and a time range.
486 * This test checks if the query method correctly retrieves NumberItems from a single MongoDB collection within a
487 * specified time range.
488 * It uses different database backends provided by the provideDatabaseBackends method.
490 * @param dbContainer The container running the MongoDB instance.
493 @MethodSource("org.openhab.persistence.mongodb.internal.DataCreationHelper#provideDatabaseBackends")
494 public void testQueryNumberItemsInOneCollectionTimeRange(DatabaseTestContainer dbContainer) {
497 SetupResult setupResult = DataCreationHelper.setupMongoDB("testCollection", dbContainer);
498 MongoDBPersistenceService service = setupResult.service;
499 MongoDatabase database = setupResult.database;
502 Mockito.when(setupResult.itemRegistry.getItem("TestItem"))
503 .thenReturn(DataCreationHelper.createNumberItem("TestItem", 0));
504 Mockito.when(setupResult.itemRegistry.getItem("TestItem2"))
505 .thenReturn(DataCreationHelper.createNumberItem("TestItem2", 0));
506 } catch (ItemNotFoundException e) {
509 service.activate(setupResult.bundleContext, setupResult.config);
511 // Get the collection
512 MongoCollection<Document> collection = database.getCollection("testCollection");
514 // Store items directly to the database with defined timestamps
515 for (int i = 0; i < 10; i++) {
516 Document obj = DataCreationHelper.createDocument("TestItem", i, LocalDate.now().minusDays(i));
517 collection.insertOne(obj);
519 Document obj2 = DataCreationHelper.createDocument("TestItem2", i * 2, LocalDate.now().minusDays(i));
520 collection.insertOne(obj2);
524 FilterCriteria filter1 = DataCreationHelper.createFilterCriteria("TestItem",
525 ZonedDateTime.now().minusDays(5), null);
526 Iterable<HistoricItem> result1 = service.query(filter1);
529 VerificationHelper.verifyQueryResult(result1, 4, -1, 5);
536 * Tests the query method of MongoDBPersistenceService with NumberItems in a single collection and a state equals
539 * This test checks if the query method correctly retrieves NumberItems from a single MongoDB collection that match
541 * It uses different database backends provided by the provideDatabaseBackends method.
543 * @param dbContainer The container running the MongoDB instance.
546 @MethodSource("org.openhab.persistence.mongodb.internal.DataCreationHelper#provideDatabaseBackends")
547 public void testQueryNumberItemsInOneCollectionStateEquals(DatabaseTestContainer dbContainer) {
550 SetupResult setupResult = DataCreationHelper.setupMongoDB("testCollection", dbContainer);
551 MongoDBPersistenceService service = setupResult.service;
552 MongoDatabase database = setupResult.database;
555 Mockito.when(setupResult.itemRegistry.getItem("TestItem"))
556 .thenReturn(DataCreationHelper.createNumberItem("TestItem", 0));
557 } catch (ItemNotFoundException e) {
560 service.activate(setupResult.bundleContext, setupResult.config);
562 // Get the collection
563 MongoCollection<Document> collection = database.getCollection("testCollection");
565 // Store items directly to the database with defined timestamps
566 for (int i = 0; i < 10; i++) {
567 Document obj = DataCreationHelper.createDocument("TestItem", i, LocalDate.now().minusDays(i));
568 collection.insertOne(obj);
571 Document obj = DataCreationHelper.createDocument("TestItem", 4.0, LocalDate.now());
572 collection.insertOne(obj);
575 FilterCriteria filter1 = DataCreationHelper.createFilterCriteria("TestItem", null, null);
576 filter1.setState(new DecimalType(4.0));
577 filter1.setOperator(FilterCriteria.Operator.EQ);
579 Iterable<HistoricItem> result1 = service.query(filter1);
582 VerificationHelper.verifyQueryResult(result1, 4, 0, 2);
589 * Tests the store method of the MongoDBPersistenceService with all types of openHAB items.
590 * Each item is stored in the collection in the MongoDB database.
592 * @param item The item to store in the database.
595 @MethodSource("org.openhab.persistence.mongodb.internal.DataCreationHelper#provideOpenhabItemTypes")
596 public void testStoreAllOpenhabItemTypesSingleCollection(GenericItem item) {
598 DatabaseTestContainer dbContainer = new DatabaseTestContainer(new MemoryBackend());
600 SetupResult setupResult = DataCreationHelper.setupMongoDB("testCollection", dbContainer);
601 MongoDBPersistenceService service = setupResult.service;
602 MongoDatabase database = setupResult.database;
604 service.activate(setupResult.bundleContext, setupResult.config);
607 service.store(item, null);
610 MongoCollection<Document> collection = database.getCollection("testCollection");
611 List<Document> documents = (ArrayList<Document>) collection.find().into(new ArrayList<>());
613 assertEquals(1, documents.size()); // Assert that there is only one document
615 Document insertedDocument = documents.get(0); // Get the first (and only) document
617 VerificationHelper.verifyDocument(insertedDocument, item.getName(), item.getState());
624 * Tests the store and query method for various image sizes of the MongoDBPersistenceService
625 * Each item is queried with the type from one collection in the MongoDB database.
627 * @param item The item to store in the database.
630 @MethodSource("org.openhab.persistence.mongodb.internal.DataCreationHelper#provideOpenhabImageItemsInDifferentSizes")
631 public void testStoreAndQueryyLargerImages(ImageItem item) {
633 DatabaseTestContainer dbContainer = new DatabaseTestContainer(new MemoryBackend());
635 SetupResult setupResult = DataCreationHelper.setupMongoDB("testCollection", dbContainer);
636 MongoDBPersistenceService service = setupResult.service;
638 service.activate(setupResult.bundleContext, setupResult.config);
640 Mockito.when(setupResult.itemRegistry.getItem(item.getName())).thenReturn(item);
641 } catch (ItemNotFoundException e) {
644 service.store(item, null);
645 } catch (org.bson.BsonMaximumSizeExceededException e) {
646 if (item.getName().equals("ImageItem20MB")) {
655 FilterCriteria filter = DataCreationHelper.createFilterCriteria(item.getName());
656 Iterable<HistoricItem> result = service.query(filter);
659 VerificationHelper.verifyQueryResult(result, item.getState());
666 * Tests the old way of storing data and query method of the MongoDBPersistenceService with all types of openHAB
668 * Each item is queried with the type from one collection in the MongoDB database.
670 * @param item The item to store in the database.
673 @MethodSource("org.openhab.persistence.mongodb.internal.DataCreationHelper#provideOpenhabItemTypes")
674 public void testOldDataQueryAllOpenhabItemTypesSingleCollection(GenericItem item) {
676 DatabaseTestContainer dbContainer = new DatabaseTestContainer(new MemoryBackend());
678 SetupResult setupResult = DataCreationHelper.setupMongoDB("testCollection", dbContainer);
679 MongoDBPersistenceService service = setupResult.service;
680 MongoDatabase database = setupResult.database;
682 service.activate(setupResult.bundleContext, setupResult.config);
684 Mockito.when(setupResult.itemRegistry.getItem(item.getName())).thenReturn(item);
685 } catch (ItemNotFoundException e) {
687 MongoCollection<Document> collection = database.getCollection("testCollection");
688 DataCreationHelper.storeOldData(collection, item.getName(), item.getState());
689 // after storing, we have to adjust the expected values for ImageItems, ColorItems as well as DateTimeItems
690 if (item instanceof ImageItem) {
691 item.setState(new RawType(new byte[0], "application/octet-stream"));
692 } else if (item instanceof ColorItem) {
693 item.setState(new HSBType("0,0,0"));
697 FilterCriteria filter = DataCreationHelper.createFilterCriteria(item.getName());
698 Iterable<HistoricItem> result = service.query(filter);
701 if (item instanceof DateTimeItem) {
702 // verify just the date part
703 assertEquals(((DateTimeType) item.getState()).getZonedDateTime().toLocalDate(),
704 ((DateTimeType) result.iterator().next().getState()).getZonedDateTime().toLocalDate());
706 VerificationHelper.verifyQueryResult(result, item.getState());
714 * Tests the writting of NumberItems including units
715 * Each item should be written to the database with the unit information
717 * @param item The item to store in the database.
720 public void testStoreNumberItemWithUnit() {
722 DatabaseTestContainer dbContainer = new DatabaseTestContainer(new MemoryBackend());
724 SetupResult setupResult = DataCreationHelper.setupMongoDB("testCollection", dbContainer);
725 MongoDBPersistenceService service = setupResult.service;
726 MongoDatabase database = setupResult.database;
728 service.activate(setupResult.bundleContext, setupResult.config);
729 MongoCollection<Document> collection = database.getCollection("testCollection");
731 NumberItem item = DataCreationHelper.createNumberItem("Number:Energy", "TestItem",
732 new QuantityType<>("10.1 kWh"));
735 service.store(item, null);
738 List<Document> documents = (ArrayList<Document>) collection.find().into(new ArrayList<>());
740 assertEquals(1, documents.size()); // Assert that there is only one document
742 Document insertedDocument = documents.get(0); // Get the first (and only) document
744 assertEquals(10.1, insertedDocument.get(MongoDBFields.FIELD_VALUE));
745 assertEquals("kWh", insertedDocument.get(MongoDBFields.FIELD_UNIT));
752 * Tests the reading of NumberItems including units
753 * Each item should be written to the database with the unit information
755 * @param item The item to store in the database.
758 public void testQueryNumberItemWithUnit() {
760 DatabaseTestContainer dbContainer = new DatabaseTestContainer(new MemoryBackend());
762 SetupResult setupResult = DataCreationHelper.setupMongoDB("testCollection", dbContainer);
763 MongoDBPersistenceService service = setupResult.service;
764 MongoDatabase database = setupResult.database;
766 service.activate(setupResult.bundleContext, setupResult.config);
767 MongoCollection<Document> collection = database.getCollection("testCollection");
769 NumberItem item = DataCreationHelper.createNumberItem("Number:Energy", "TestItem",
770 new QuantityType<>("10.1 MWh"));
772 Mockito.when(setupResult.itemRegistry.getItem("TestItem")).thenReturn(item);
773 } catch (ItemNotFoundException e) {
776 Document obj = new Document();
777 obj.put(MongoDBFields.FIELD_ID, new ObjectId());
778 obj.put(MongoDBFields.FIELD_ITEM, "TestItem");
779 obj.put(MongoDBFields.FIELD_REALNAME, "TestItem");
780 obj.put(MongoDBFields.FIELD_TIMESTAMP, new Date());
781 obj.put(MongoDBFields.FIELD_VALUE, 201.5);
782 obj.put(MongoDBFields.FIELD_UNIT, "Wh");
783 collection.insertOne(obj);
786 FilterCriteria filter = DataCreationHelper.createFilterCriteria("TestItem");
787 Iterable<HistoricItem> result = service.query(filter);
788 VerificationHelper.verifyQueryResult(result, new QuantityType<>("201.5 Wh"));
795 * Tests the toString of a MongoDBItem
798 * @param item The item to store in the database.
801 public void testHistoricItemToString() {
803 ZonedDateTime now = ZonedDateTime.now();
804 HistoricItem item = new MongoDBItem("TestItem", new DecimalType(10.1), now);
807 String result = item.toString();
810 // Jan 29, 2024, 8:43:26 PM: TestItem -> 10.1
811 String expected = DateFormat.getDateTimeInstance().format(Date.from(now.toInstant())) + ": TestItem -> 10.1";
812 assertEquals(expected, result);
816 * Test the store method which stores a item state as well as a timestampe (ZonedDateTime) and check the result in
820 public void testStoreItemWithTimestamp() {
822 DatabaseTestContainer dbContainer = new DatabaseTestContainer(new MemoryBackend());
824 SetupResult setupResult = DataCreationHelper.setupMongoDB(null, dbContainer);
825 MongoDBPersistenceService service = setupResult.service;
826 MongoDatabase database = setupResult.database;
828 service.activate(setupResult.bundleContext, setupResult.config);
830 Mockito.when(setupResult.itemRegistry.getItem("TestItem"))
831 .thenReturn(DataCreationHelper.createNumberItem("TestItem", 0));
832 } catch (ItemNotFoundException e) {
836 NumberItem item = DataCreationHelper.createNumberItem("TestItem", 10.1);
837 DecimalType historicState = new DecimalType(11110.1);
838 ZonedDateTime now = ZonedDateTime.now();
839 service.store(item, now, historicState);
842 MongoCollection<Document> collection = database.getCollection("TestItem");
843 List<Document> documents = (ArrayList<Document>) collection.find().into(new ArrayList<>());
845 assertEquals(1, documents.size()); // Assert that there is only one document
847 Document insertedDocument = documents.get(0); // Get the first (and only) document
849 VerificationHelper.verifyDocument(insertedDocument, "TestItem", historicState);
850 assertEquals(Date.from(now.toInstant()), insertedDocument.get(MongoDBFields.FIELD_TIMESTAMP));
857 * Test the store method which stores a item state as well as a timestampe (ZonedDateTime) and check the result in
861 public void testStoreItemWithTimestampAndAlias() {
863 DatabaseTestContainer dbContainer = new DatabaseTestContainer(new MemoryBackend());
865 SetupResult setupResult = DataCreationHelper.setupMongoDB(null, dbContainer);
866 MongoDBPersistenceService service = setupResult.service;
867 MongoDatabase database = setupResult.database;
869 service.activate(setupResult.bundleContext, setupResult.config);
871 Mockito.when(setupResult.itemRegistry.getItem("TestItem"))
872 .thenReturn(DataCreationHelper.createNumberItem("TestItem", 0));
873 } catch (ItemNotFoundException e) {
877 NumberItem item = DataCreationHelper.createNumberItem("TestItem", 10.1);
878 DecimalType historicState = new DecimalType(11110.1);
879 ZonedDateTime now = ZonedDateTime.now();
880 service.store(item, now, historicState, "AliasName");
883 MongoCollection<Document> collection = database.getCollection("TestItem");
884 List<Document> documents = (ArrayList<Document>) collection.find().into(new ArrayList<>());
886 assertEquals(1, documents.size()); // Assert that there is only one document
888 Document insertedDocument = documents.get(0); // Get the first (and only) document
890 VerificationHelper.verifyDocumentWithAlias(insertedDocument, "AliasName", "TestItem", historicState);
891 assertEquals(Date.from(now.toInstant()), insertedDocument.get(MongoDBFields.FIELD_TIMESTAMP));
898 * Test the remove method to remove one item from the database
901 public void testremoveOneItem() {
903 DatabaseTestContainer dbContainer = new DatabaseTestContainer(new MemoryBackend());
905 SetupResult setupResult = DataCreationHelper.setupMongoDB("testcollection", dbContainer);
906 MongoDBPersistenceService service = setupResult.service;
907 MongoDatabase database = setupResult.database;
909 service.activate(setupResult.bundleContext, setupResult.config);
911 for (double i = 0; i < 10.00; i += 0.3) {
912 service.store(DataCreationHelper.createNumberItem("TestItem", i));
914 service.store(DataCreationHelper.createNumberItem("TestItemOther", 10.1));
917 service.remove(DataCreationHelper.createFilterCriteria("TestItem", null, null));
920 MongoCollection<Document> collection = database.getCollection("testcollection");
922 List<Document> documents = (ArrayList<Document>) collection.find().into(new ArrayList<>());
924 assertEquals(1, documents.size()); // Assert that there is the other document
926 VerificationHelper.verifyDocument(documents.get(0), "TestItemOther", 10.1);
933 * Test the remove method to remove values of a given timerange for one item
936 public void testremoveATimeRangeFromOneItem() {
938 DatabaseTestContainer dbContainer = new DatabaseTestContainer(new MemoryBackend());
940 SetupResult setupResult = DataCreationHelper.setupMongoDB("testcollection", dbContainer);
941 MongoDBPersistenceService service = setupResult.service;
942 MongoDatabase database = setupResult.database;
944 service.activate(setupResult.bundleContext, setupResult.config);
946 List<PersistenceTestItem> testDataList = DataCreationHelper.createTestData(service, "TestItem",
950 // Calculate the start and end dates
951 ZonedDateTime startDate = ZonedDateTime.now().plusDays(3).truncatedTo(ChronoUnit.DAYS);
952 ZonedDateTime endDate = ZonedDateTime.now().plusDays(17).truncatedTo(ChronoUnit.DAYS).plusDays(1)
955 // Create the filter and remove the data
956 service.remove(DataCreationHelper.createFilterCriteria("TestItem", startDate, endDate));
959 MongoCollection<Document> collection = database.getCollection("testcollection");
961 // Query the database for all data points
962 List<Document> documents = (ArrayList<Document>) collection.find().into(new ArrayList<>());
964 // Create a set of the returned data points
965 Set<PersistenceTestItem> returnedData = documents.stream()
966 .map(doc -> new PersistenceTestItem(doc.getString(MongoDBFields.FIELD_ITEM),
967 ZonedDateTime.ofInstant(doc.getDate(MongoDBFields.FIELD_TIMESTAMP).toInstant(),
968 ZoneId.systemDefault()),
969 doc.getDouble(MongoDBFields.FIELD_VALUE)))
970 .collect(Collectors.toSet());
972 // Create a set of the expected data points
973 Set<PersistenceTestItem> expectedData = testDataList
974 .stream().filter(testData -> !(testData.itemName.equals("TestItem")
975 && testData.date.isAfter(startDate) && testData.date.isBefore(endDate)))
976 .collect(Collectors.toSet());
978 for (PersistenceTestItem expectedItem : expectedData) {
979 // Assert that this item is in the returned data
980 assertTrue(returnedData.contains(expectedItem),
981 "Expected item not found in returned data: " + expectedItem);
984 // Iterate over the returned data
985 for (PersistenceTestItem returnedItem : returnedData) {
986 // Assert that this item is in the expected data
987 assertTrue(expectedData.contains(returnedItem),
988 "Unexpected item found in returned data: " + returnedItem);