Audit logs are saved asynchronously via executor.submit() in AuditLogServiceImpl.
Three tests were asserting log counts immediately after HTTP API calls, creating
a race condition where the last audit log write may not have completed yet.
Replace bare assertions with Awaitility.await().atMost(TIMEOUT, ...).untilAsserted()
in testAuditLogs, testAuditLogs_byTenantIdAndEntityId, and
testAuditLogs_byTenantIdAndEntityId_Sysadmin (confirmed broken: expected 2, got 1).
Also replace the hardcoded 10s timeout in testAuditLogsSysAdmin with the TIMEOUT constant.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Tests like testFindTenantsByTitle create 261 tenants and delete them via
deleteEntitiesAsync, which only waits for HTTP responses — not housekeeper
completion. Each tenant deletion submits ~30 TenantEntitiesDeletionHousekeeper
tasks (~7800 tasks total), which cascade further. The teardown's deleteTenant
then waits for lag==0 with a 90s timeout, which is insufficient for this
backlog and causes ConditionTimeoutException.
Fix: add awaitHousekeeperDrained() (5-min timeout) called at the start of
teardownWebTest so any pending housekeeper work from the test body drains
before per-tenant teardown deletions begin.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
doGet/doGetAsyncTyped assert HTTP 200 internally, so any non-200 response
throws AssertionError which Awaitility re-throws immediately instead of
continuing to poll.
Add .ignoreExceptions() to three additional await() polling loops that
call HTTP helpers:
- AbstractMqttV5ClientSparkplugAttributesTest: two doGetAsyncTyped calls
polling for attribute keys after NBIRTH/DBIRTH
- AbstractMqttAttributesIntegrationTest: doGetAsyncTyped polling for
attribute values after client publish
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
doGet(url, Class) asserts HTTP 200 internally, so when the Sparkplug
device hasn't been created yet the method throws AssertionError instead
of returning null. Awaitility propagates Error immediately rather than
continuing to poll, causing the test to fail after ~3 s instead of
retrying for up to 200 s.
Add .ignoreExceptions() to both await() calls in
connectClientWithCorrectAccessTokenWithNDEATHCreatedDevices and
connectClientWithCorrectAccessTokenWithNDEATHWithAliasCreatedDevices so
that a transient 404 is treated as "condition not yet met" and polling
continues as intended.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
After the MQTT transport closes the session on RPC delivery timeout,
the server re-queues the RPC asynchronously. The test was asserting
the RPC status immediately after the client disconnect latch fired,
before the server-side re-queuing had completed — so the status was
still SENT instead of the expected QUEUED.
Replace the direct doGet assertion with an Awaitility poll that waits
up to DEFAULT_WAIT_TIMEOUT_SECONDS for the status to become QUEUED.
Fixes flaky: MqttV5CloseTransportSessionOnRpcDeliveryTimeoutIntegrationTest
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When building with -T6, multiple JS modules run yarn install concurrently.
The --mutex network flag serializes yarn processes, but if node_modules from
a previous build (or a different branch/version) is left on disk, yarn may
skip reinstalling packages — including devDependencies — treating the stale
state as up-to-date. This causes tools like tsc to be missing at build time.
Configure maven-clean-plugin to delete node_modules during mvn clean for
all JS modules (ui-ngx, msa/js-executor, msa/web-ui). Yarn restores from
its global cache (~/.cache/yarn), so the overhead is relinking only.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Audit logs are saved asynchronously via executor.submit() in AuditLogServiceImpl,
so querying immediately after tenant profile creation could miss logs not yet persisted.
Replace direct assertEquals with Awaitility.await().atMost(10s).untilAsserted() to
tolerate the async save delay.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When Execute RPC is sent to FW Update resource (/5/0/2), the test client's
startUpdating() scheduled the client stop with 0 delay. This caused a race
where the client stopped before the CoAP Execute response (2.04 Changed)
was delivered to the server, resulting in RequestCanceledException and
INTERNAL_SERVER_ERROR instead of CHANGED.
Adding a 1-second delay before leshanClient.stop() ensures the CoAP
response is transmitted and received before the client disconnects, fixing
the flaky testExecuteUpdateFWById_Result_CHANGED test.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Using the same connection for both SCAN cursor iteration and GET value
fetches causes Jedis 5.x response-ordering corruption: the SCAN response
parser receives a GET response (byte[]) where it expects a List, and vice
versa, resulting in ClassCastException on startup.
Fix: open two connections per getAll() call — one dedicated to the scan
cursor and one for value fetches — eliminating any interleaving.
Affected: TbRedisLwM2MClientStore, TbRedisLwM2MModelConfigStore,
TbLwM2mRedisRegistrationStore.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Tests that read shared static state (e.g. testAllowedUrls with 8.8.8.8)
could run concurrently with tests that mutate it (e.g. testAdditionalBlockedSingleIp),
causing intermittent failures. Class-level @ResourceLock serializes all tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>