Make setupSsl package-private so the test can call it directly, ensuring
tests exercise the real production code path.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add RSA_4096 and EC_P256 alongside RSA_2048 and EC_P384
- Parameterize encrypted key tests (RSA-only, EC encrypted keys
are a pre-existing PemSslCredentials limitation)
- 14 test scenarios total
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add EC_P384 key type alongside RSA_2048
- Parameterize separateCertAndKeyFiles and combinedPemFile tests
- Write private keys in PKCS#8 format for EC compatibility
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use forPort(0) instead of TestSocketUtils for random port
- Replace manual poll loop with Awaitility
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests mirror EdgeGrpcService.setupSsl() using PemSslCredentials:
- Separate cert and key files (existing behavior)
- Combined PEM file (cert + key)
- Encrypted private key with key_password
- Error when no private key found
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Keep privateKeyFile.pem as the default so existing users with
separate cert/key file configs are not affected.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reuse PemSslCredentials (already handles combined PEM, separate files,
and encrypted keys) instead of duplicating PEM parsing logic.
Wire it into gRPC via GrpcSslContexts + KeyManagerFactory.
- Make private_key config optional (default empty) for combined PEM
- Add key_password config for encrypted private keys
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- TimeseriesServiceNoSqlTest.shouldSaveEntryOfEachTypeWithTtl: await
tsService.save() with bounded .get(MAX_TIMEOUT, TimeUnit.SECONDS)
- EntityServiceTest.testFindTenantTelemetry: await timeseriesService.save()
and attributesService.save() with .get(TIMEOUT, TimeUnit.SECONDS) to
prevent both the race condition and an indefinite hang
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Variables reassigned in a loop cannot be captured in lambda expressions.
Introduce finalSavedDevice and finalTenantProfile as effectively final copies
before use in Awaitility.await() lambdas.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace magic number 5 with a named constant that explains intent:
small enough to force multiple pages and verify pagination loop correctness.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
EntityViewControllerTest was importing MQTT_PORT from AbstractMqttIntegrationTest,
a static final field initialized once per JVM. When running in the same Surefire
fork alongside other test classes that also use this constant (e.g. MqttGatewayRateLimitsTest,
DeviceEdgeTest), each class gets a different Spring context key but all try to bind
MqttTransportService to the same port, causing BindException.
Fix: define a private static MQTT_PORT/MQTT_URL directly in EntityViewControllerTest
so its Spring context gets its own independently allocated port.
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>
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>