Skip to content

[mapdb] Improve shutdown handling and add tests#20153

Merged
lsiepel merged 9 commits intoopenhab:mainfrom
holgerfriedrich:pr-mapdb-tests
Feb 14, 2026
Merged

[mapdb] Improve shutdown handling and add tests#20153
lsiepel merged 9 commits intoopenhab:mainfrom
holgerfriedrich:pr-mapdb-tests

Conversation

@holgerfriedrich
Copy link
Member

@holgerfriedrich holgerfriedrich commented Jan 27, 2026

  • Track all storage requests and make sure we wait for them to complete before shutting down the database.
    This might delay the DB shutdown up to 30 seconds. New storage requests issued during shutdown will cause a log entry (on info level).
  • Tests for the MapDb service.
    Similar approach as in [rrd4j] Add unit tests #20142.
    Includes code coverage metrics.
grafik

Signed-off-by: Holger Friedrich <mail@holger-friedrich.de>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@holgerfriedrich
Copy link
Member Author

holgerfriedrich commented Jan 30, 2026

some valid comments from copilot, I will have a look

holgerfriedrich and others added 2 commits February 6, 2026 21:57
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>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines 98 to 107
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());
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Suggested change
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!

Copilot uses AI. Check for mistakes.

@AfterEach
void tearDown() throws Exception {
if (service != null) {
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
if (service != null) {
if (service != null) {
// Give asynchronous persistence enough time to complete before closing the DB
Thread.sleep(STORAGE_TIMEOUT_MS);

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be fine

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>
@holgerfriedrich holgerfriedrich changed the title [mapdb] Add unit tests [mapdb] Improve shutdown handling and add tests Feb 8, 2026
@holgerfriedrich holgerfriedrich added the enhancement An enhancement or new feature for an existing add-on label Feb 8, 2026
Signed-off-by: Holger Friedrich <mail@holger-friedrich.de>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +70 to +75
@BeforeEach
void setUp() throws Exception {
// Create service and activate OSGi lifecycle manually for tests
service = new MapDbPersistenceService();
service.activate();
}
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using different item names for all tests runs now

Comment on lines 96 to 101
public void activate() {
logger.debug("MapDB persistence service is being activated");
active = true;

try {
Files.createDirectories(DB_DIR);
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think this is fine as it is

Signed-off-by: Holger Friedrich <mail@holger-friedrich.de>
@holgerfriedrich
Copy link
Member Author

holgerfriedrich commented Feb 8, 2026

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 store() is called during shutdown, maybe it should be a debug.

Copy link
Contributor

@lsiepel lsiepel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, LGTM

@lsiepel lsiepel merged commit 6b541b0 into openhab:main Feb 14, 2026
2 checks passed
@lsiepel lsiepel added this to the 5.2 milestone Feb 14, 2026
@holgerfriedrich holgerfriedrich deleted the pr-mapdb-tests branch February 14, 2026 13:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement An enhancement or new feature for an existing add-on test

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants