[mapdb] Improve shutdown handling and add tests#20153
Conversation
Signed-off-by: Holger Friedrich <mail@holger-friedrich.de>
There was a problem hiding this comment.
Pull request overview
This pull request adds unit tests for the MapDB persistence service along with JaCoCo code coverage configuration. The tests follow a similar pattern to the referenced PR #20142 for RRD4J persistence, providing smoke tests for basic store and query operations.
Changes:
- Added comprehensive unit tests for MapDbPersistenceService covering store/retrieve operations for different item types (Number, String, Switch)
- Configured JaCoCo Maven plugin with code instrumentation for test coverage reporting
- Added test coverage for service metadata methods (getId, getLabel)
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 8 comments.
| File | Description |
|---|---|
| bundles/org.openhab.persistence.mapdb/src/test/java/org/openhab/persistence/mapdb/MapDbPersistenceServiceTest.java | New test class with 8 test methods covering persistence operations for different item types, query operations, and service metadata |
| bundles/org.openhab.persistence.mapdb/pom.xml | Added JaCoCo dependencies and Maven plugin configuration for code coverage reporting with offline instrumentation |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
...rsistence.mapdb/src/test/java/org/openhab/persistence/mapdb/MapDbPersistenceServiceTest.java
Outdated
Show resolved
Hide resolved
...rsistence.mapdb/src/test/java/org/openhab/persistence/mapdb/MapDbPersistenceServiceTest.java
Outdated
Show resolved
Hide resolved
...rsistence.mapdb/src/test/java/org/openhab/persistence/mapdb/MapDbPersistenceServiceTest.java
Outdated
Show resolved
Hide resolved
...rsistence.mapdb/src/test/java/org/openhab/persistence/mapdb/MapDbPersistenceServiceTest.java
Outdated
Show resolved
Hide resolved
...rsistence.mapdb/src/test/java/org/openhab/persistence/mapdb/MapDbPersistenceServiceTest.java
Outdated
Show resolved
Hide resolved
...rsistence.mapdb/src/test/java/org/openhab/persistence/mapdb/MapDbPersistenceServiceTest.java
Outdated
Show resolved
Hide resolved
...rsistence.mapdb/src/test/java/org/openhab/persistence/mapdb/MapDbPersistenceServiceTest.java
Outdated
Show resolved
Hide resolved
...rsistence.mapdb/src/test/java/org/openhab/persistence/mapdb/MapDbPersistenceServiceTest.java
Outdated
Show resolved
Hide resolved
|
some valid comments from copilot, I will have a look |
Signed-off-by: Holger Friedrich <mail@holger-friedrich.de>
Refs: openhab#20181 Signed-off-by: Holger Friedrich <mail@holger-friedrich.de> Co-authored-by: Copilot <Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
...rsistence.mapdb/src/test/java/org/openhab/persistence/mapdb/MapDbPersistenceServiceTest.java
Show resolved
Hide resolved
| try { | ||
| Iterable<HistoricItem> results = service.query(criteria); | ||
| if (results.iterator().hasNext()) { | ||
| long elapsed = System.currentTimeMillis() - startTime; | ||
| logger.info("Storage completed for '{}' after {}ms ({} attempts)", itemName, elapsed, attempts); | ||
| return; // Success! | ||
| } | ||
| } catch (Exception e) { | ||
| // Query might fail if data not ready yet, continue polling | ||
| logger.debug("Query attempt {} failed: {}", attempts, e.getMessage()); |
There was a problem hiding this comment.
waitForStorage() catches any Exception from service.query() and keeps polling. For MapDbPersistenceService.query() an exception is unexpected (it typically indicates failed activation / null map) and swallowing it turns an immediate failure into a 20s timeout. Consider letting exceptions fail the test (or only retry on specific, expected transient errors).
| try { | |
| Iterable<HistoricItem> results = service.query(criteria); | |
| if (results.iterator().hasNext()) { | |
| long elapsed = System.currentTimeMillis() - startTime; | |
| logger.info("Storage completed for '{}' after {}ms ({} attempts)", itemName, elapsed, attempts); | |
| return; // Success! | |
| } | |
| } catch (Exception e) { | |
| // Query might fail if data not ready yet, continue polling | |
| logger.debug("Query attempt {} failed: {}", attempts, e.getMessage()); | |
| Iterable<HistoricItem> results = service.query(criteria); | |
| if (results.iterator().hasNext()) { | |
| long elapsed = System.currentTimeMillis() - startTime; | |
| logger.info("Storage completed for '{}' after {}ms ({} attempts)", itemName, elapsed, attempts); | |
| return; // Success! |
|
|
||
| @AfterEach | ||
| void tearDown() throws Exception { | ||
| if (service != null) { |
There was a problem hiding this comment.
waitForStorage() returns as soon as query() can read the value from the in-memory map, but store() persists asynchronously and only calls db.commit() after updating the map. This means the test may proceed (and tearDown() may close the DB) before the commit completes, leading to racy failures/corrupted storage. Consider adding a deterministic sync point (e.g., reopen the service and query again, or otherwise wait until the background store task has fully completed) before deactivating.
| if (service != null) { | |
| if (service != null) { | |
| // Give asynchronous persistence enough time to complete before closing the DB | |
| Thread.sleep(STORAGE_TIMEOUT_MS); |
...rsistence.mapdb/src/test/java/org/openhab/persistence/mapdb/MapDbPersistenceServiceTest.java
Outdated
Show resolved
Hide resolved
Signed-off-by: Holger Friedrich <mail@holger-friedrich.de>
Signed-off-by: Holger Friedrich <mail@holger-friedrich.de>
…before closing Signed-off-by: Holger Friedrich <mail@holger-friedrich.de>
Signed-off-by: Holger Friedrich <mail@holger-friedrich.de>
Signed-off-by: Holger Friedrich <mail@holger-friedrich.de>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @BeforeEach | ||
| void setUp() throws Exception { | ||
| // Create service and activate OSGi lifecycle manually for tests | ||
| service = new MapDbPersistenceService(); | ||
| service.activate(); | ||
| } |
There was a problem hiding this comment.
The tests reuse the same on-disk MapDB file between test cases (storage.mapdb under ${openhab.userdata}/persistence/mapdb). Since item names are reused across tests (e.g., TestNumber is used in multiple methods), a previous test run can satisfy waitForStorage() immediately and mask failures in the current test, making the suite order-dependent. Clean the MapDB storage directory/file in @BeforeEach (or use per-test unique item names / a per-test userdata folder).
There was a problem hiding this comment.
using different item names for all tests runs now
| public void activate() { | ||
| logger.debug("MapDB persistence service is being activated"); | ||
| active = true; | ||
|
|
||
| try { | ||
| Files.createDirectories(DB_DIR); |
There was a problem hiding this comment.
active is set to true at the start of activate(), but there are multiple early-return failure paths later in this method. That can leave the service in a partially-initialized state with active=true while db/map were never created, causing store() to proceed and then fail (potentially with NPE) instead of being skipped. Set active=true only after successful DB/map initialization, and ensure it is set back to false on all activation-failure returns.
There was a problem hiding this comment.
i think this is fine as it is
...ence.mapdb/src/main/java/org/openhab/persistence/mapdb/internal/MapDbPersistenceService.java
Outdated
Show resolved
Hide resolved
Signed-off-by: Holger Friedrich <mail@holger-friedrich.de>
|
Ok, from my perspecitve, I am done. I have updated the PR description. Can you please make sure that something mentioning the changed behaviour on close stays in the commit message when squashing during merge. I am still not sure about the logging on info level if |
This might delay the DB shutdown up to 30 seconds. New storage requests issued during shutdown will cause a log entry (on info level).
Similar approach as in [rrd4j] Add unit tests #20142.
Includes code coverage metrics.