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>
In Jackson 2.18.x, EXISTING_PROPERTY type info combined with the no-arg
@JsonIgnoreProperties causes the triggerType discriminator field to be
silently excluded from the serialized JSON. When the server then tries to
deserialize the POST body for /api/notification/rule, Jackson cannot find
triggerType and throws "missing type id property 'triggerType'", resulting
in a 500 for NotificationEdgeTest.testNotificationRule.
Fix by:
1. Adding @JsonProperty("triggerType") to force the field into normal bean
serialization, overriding any suppression by the type info machinery.
2. Replacing the no-arg @JsonIgnoreProperties with @JsonIgnoreProperties(
ignoreUnknown = true) so unknown properties are ignored rather than
causing errors (e.g. for forward compatibility).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Methods stubbed via Mockito spy in same-package tests must remain
package-private. Revert isSSL() to package-private; getClientAddr()
follows the same convention as getAddress().
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Rename TagsKey → tagsKey and make it private (Java naming convention)
- Make isSSL() private in MqttTransportHandler (internal use only)
- Fix double space in if (isSSL) in MqttTransportContext
- Extract getClientAddr() helper and move clientAddr computation inside
logging guards so address resolution is skipped when logging is disabled
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>