1616import static org .junit .jupiter .api .Assertions .assertNotNull ;
1717import static org .junit .jupiter .api .Assertions .assertNull ;
1818import static org .junit .jupiter .api .Assertions .assertTrue ;
19+ import static org .junit .jupiter .api .Assertions .fail ;
1920import static org .mockito .Mockito .when ;
2021
2122import java .time .ZoneId ;
3839import org .openhab .core .persistence .HistoricItem ;
3940import org .openhab .core .persistence .PersistedItem ;
4041import org .openhab .persistence .mapdb .internal .MapDbPersistenceService ;
42+ import org .slf4j .Logger ;
43+ import org .slf4j .LoggerFactory ;
4144
4245/**
4346 * Tests for {@link MapDbPersistenceService}.
4750 */
4851@ ExtendWith (MockitoExtension .class )
4952class MapDbPersistenceServiceTest {
50- static final int STORAGE_TIMEOUT_MS = 1000 ;
53+ private static final long STORAGE_TIMEOUT_MS = 20000 ; // 20 seconds for CI
54+ private static final long POLL_INTERVAL_MS = 250 ; // Check every 250ms
55+
56+ private final Logger logger = LoggerFactory .getLogger (MapDbPersistenceServiceTest .class );
5157
5258 @ Mock
5359 private ItemRegistry itemRegistry ;
@@ -70,6 +76,45 @@ void setUp() throws Exception {
7076 service .activate ();
7177 }
7278
79+ /**
80+ * Waits for data to be persisted by polling the database.
81+ * This is more robust than Thread.sleep() in CI environments with resource contention.
82+ *
83+ * @param itemName the name of the item to check
84+ * @param timeoutMs maximum time to wait in milliseconds
85+ * @throws InterruptedException if interrupted while waiting
86+ */
87+ private void waitForStorage (String itemName , long timeoutMs ) throws InterruptedException {
88+ long startTime = System .currentTimeMillis ();
89+ int attempts = 0 ;
90+
91+ while (System .currentTimeMillis () - startTime < timeoutMs ) {
92+ attempts ++;
93+
94+ FilterCriteria criteria = new FilterCriteria ();
95+ criteria .setItemName (itemName );
96+ criteria .setPageSize (1 );
97+
98+ try {
99+ Iterable <HistoricItem > results = service .query (criteria );
100+ if (results .iterator ().hasNext ()) {
101+ long elapsed = System .currentTimeMillis () - startTime ;
102+ logger .info ("Storage completed for '{}' after {}ms ({} attempts)" , itemName , elapsed , attempts );
103+ return ; // Success!
104+ }
105+ } catch (Exception e ) {
106+ // Query might fail if data not ready yet, continue polling
107+ logger .debug ("Query attempt {} failed: {}" , attempts , e .getMessage ());
108+ }
109+
110+ Thread .sleep (POLL_INTERVAL_MS );
111+ }
112+
113+ long elapsed = System .currentTimeMillis () - startTime ;
114+ fail (String .format ("Data for item '%s' was not persisted within %dms (%d polling attempts)." , itemName , elapsed ,
115+ attempts ));
116+ }
117+
73118 private void configureNumberItem () throws Exception {
74119 when (numberItem .getName ()).thenReturn ("TestNumber" );
75120 when (numberItem .getState ()).thenReturn (new DecimalType (42.5 ));
@@ -100,7 +145,7 @@ void storeAndRetrieveNumberValue() throws Exception {
100145 service .store (numberItem );
101146
102147 // Wait for background storage to complete
103- Thread . sleep ( STORAGE_TIMEOUT_MS );
148+ waitForStorage ( numberItem . getName (), STORAGE_TIMEOUT_MS );
104149
105150 // Query the value back
106151 FilterCriteria criteria = new FilterCriteria ();
@@ -128,7 +173,7 @@ void storeAndRetrieveStringValue() throws Exception {
128173 service .store (stringItem );
129174
130175 // Wait for background storage to complete
131- Thread . sleep ( STORAGE_TIMEOUT_MS );
176+ waitForStorage ( stringItem . getName (), STORAGE_TIMEOUT_MS );
132177
133178 // Query the value back
134179 FilterCriteria criteria = new FilterCriteria ();
@@ -161,7 +206,7 @@ void storeAndRetrieveSwitchValue() throws Exception {
161206 service .store (switchItem );
162207
163208 // Wait for background storage to complete
164- Thread . sleep ( STORAGE_TIMEOUT_MS );
209+ waitForStorage ( switchItem . getName (), STORAGE_TIMEOUT_MS );
165210
166211 // Query the value back
167212 FilterCriteria criteria = new FilterCriteria ();
@@ -194,7 +239,7 @@ void queryWithTimeRange() throws Exception {
194239 service .store (numberItem );
195240
196241 // Wait for background storage to complete
197- Thread . sleep ( STORAGE_TIMEOUT_MS );
242+ waitForStorage ( numberItem . getName (), STORAGE_TIMEOUT_MS );
198243
199244 // Query with time range
200245 FilterCriteria criteria = new FilterCriteria ();
0 commit comments