From 37fa0e6a2b3b2a0a1f34587dd2f9a7cfdb83bb25 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Mon, 23 Feb 2026 22:39:47 +0200 Subject: [PATCH] lwm2m - fix bug flaky tests --- .../transport/lwm2m/client/FwLwM2MDevice.java | 16 +++++++++------- .../ota/AbstractOtaLwM2MIntegrationTest.java | 19 +++++++++++++++---- .../ota/sql/Ota5LwM2MIntegrationTest.java | 4 +++- .../security/sql/PskLwm2mIntegrationTest.java | 15 ++++++++++++++- 4 files changed, 41 insertions(+), 13 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java index 9265893fa2..9bed9bc483 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java @@ -140,22 +140,22 @@ public class FwLwM2MDevice extends BaseInstanceEnabler implements Destroyable { } private void startDownloading() { - long delay = 0; + long delay = 500; // Step 1: state = 1 scheduler.schedule(() -> { - state.set(1); + state.set(1); // DOWNLOADING fireResourceChange(3); log.info("Downloading started: state=[{}]", state.get()); - }, delay, TimeUnit.MILLISECONDS); + }, delay, TimeUnit.MILLISECONDS); // 500 ms - delay += 100; // next step after 100 ms + delay += 1000; // next step after 100 ms // Step 2: state = 2 scheduler.schedule(() -> { - state.set(2); + state.set(2); // DOWNLOADED fireResourceChange(3); log.info("Downloading in progress: state=[{}]", state.get()); - }, delay, TimeUnit.MILLISECONDS); + }, delay, TimeUnit.MILLISECONDS); // 1500 ms } @@ -177,6 +177,8 @@ public class FwLwM2MDevice extends BaseInstanceEnabler implements Destroyable { this.leshanClient.start(); // Delayed reset pkgName/pkgVersion, after reboot + registration + // If a client stops, ThingsBoard can mark it as Offline. + // A new registration may take a few seconds. scheduler.schedule(() -> { this.pkgName = this.pkgNameDef; fireResourceChange(6); @@ -186,7 +188,7 @@ public class FwLwM2MDevice extends BaseInstanceEnabler implements Destroyable { log.info("FW resources updating to new values: pkgName=[{}], pkgVersion=[{}]", this.pkgName, this.pkgVersion); - }, 15, TimeUnit.SECONDS); // 15 sec — safe timing + }, 5, TimeUnit.SECONDS); // 5 sec — safe timing } } catch (Exception e) { log.error("Error during firmware update", e); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/AbstractOtaLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/AbstractOtaLwM2MIntegrationTest.java index 1d49092074..7a32a48324 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/AbstractOtaLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/AbstractOtaLwM2MIntegrationTest.java @@ -196,12 +196,23 @@ public abstract class AbstractOtaLwM2MIntegrationTest extends AbstractLwM2MInteg } protected boolean predicateForStatuses(List ts) { - List statuses = ts.stream() + if (ts == null || ts.isEmpty()) return false; + + List statuses = ts.stream() .sorted(Comparator.comparingLong(TsKvEntry::getTs)) .map(KvEntry::getValueAsString) - .map(OtaPackageUpdateStatus::valueOf) .collect(Collectors.toList()); - log.warn("{}", statuses); - return statuses.containsAll(expectedStatuses); + + // If we haven't received UPDATED yet + if (!statuses.contains(OtaPackageUpdateStatus.UPDATED.name())) { + return false; + } + + log.warn("Captured statuses: {}", statuses); + + // Перевірка, що всі очікувані статуси хоча б раз промайнули + return expectedStatuses.stream() + .map(Enum::name) + .allMatch(statuses::contains); } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/Ota5LwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/Ota5LwM2MIntegrationTest.java index 9cbd02f613..c041ba1277 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/Ota5LwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/Ota5LwM2MIntegrationTest.java @@ -103,8 +103,10 @@ public class Ota5LwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest { expectedStatuses = Arrays.asList(QUEUED, INITIATED, DOWNLOADING, DOWNLOADED, UPDATING, UPDATED); List ts = await("await on timeseries for FW") - .atMost(TIMEOUT, TimeUnit.SECONDS) + .atMost(60, TimeUnit.SECONDS) // Increase the timeout to 60 sec + .pollInterval(1, TimeUnit.SECONDS) // Poll once per second .until(() -> getFwSwStateTelemetryFromAPI(device.getId().getId(), "fw_state"), this::predicateForStatuses); + log.warn("Object5: Got the ts: {}", ts); } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java index 29beace952..72d34317bc 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java @@ -161,6 +161,20 @@ public class PskLwm2mIntegrationTest extends AbstractSecurityLwM2MIntegrationTes clientCredentials.setKey(keyPsk); Lwm2mDeviceProfileTransportConfiguration transportConfiguration = getTransportConfiguration(OBSERVE_ATTRIBUTES_WITHOUT_PARAMS, getBootstrapServerCredentialsSecure(PSK, NONE)); DeviceProfile deviceProfile = createLwm2mDeviceProfile("profileFor" + clientEndpoint, transportConfiguration); + + // Wait for the profile to become available. This synchronizes asynchronous processes and prevents TenantNotFoundException during tearDown. + org.awaitility.Awaitility.await() + .atMost(10, java.util.concurrent.TimeUnit.SECONDS) + .pollInterval(200, java.util.concurrent.TimeUnit.MILLISECONDS) + .until(() -> { + try { + String url = "/api/deviceProfile/" + deviceProfile.getId().getId().toString(); + return doGet(url, DeviceProfile.class) != null; + } catch (Exception e) { + return false; + } + }); + LwM2MDeviceCredentials deviceCredentials = getDeviceCredentialsSecure(clientCredentials, null, null, PSK, false); MvcResult result = createDeviceWithMvcResult(deviceCredentials, clientEndpoint, deviceProfile.getId()); assertEquals(HttpServletResponse.SC_BAD_REQUEST, result.getResponse().getStatus()); @@ -168,7 +182,6 @@ public class PskLwm2mIntegrationTest extends AbstractSecurityLwM2MIntegrationTes assertTrue(result.getResponse().getContentAsString().contains(msgExpected)); } - // Bootstrap + Lwm2m @Test public void testWithPskConnectBsSuccess_UpdateTwoSectionsBootstrapAndLm2m_ConnectLwm2mSuccess() throws Exception {