Add GOPACSHandler day-ahead UFTP flow tests#42
Conversation
…he example message format
There was a problem hiding this comment.
Pull request overview
Adds isolated Spock-based test coverage for the GOPACS UFTP day-ahead message flow on the EMS/AGR side by driving real signed UFTP v3.0.0 XML payloads through GOPACSHandler.processRawMessage, and introduces a test-support constructor to wire collaborators without container/OAuth/JAX-RS setup.
Changes:
- Add
GOPACSHandlerTestcovering FlexRequest → (FlexRequestResponse + FlexOffer), FlexOfferResponse handling, FlexOrder flows, and out-of-scope congestion point dropping. - Add a protected test-support constructor on
GOPACSHandlerto allow exercising message handling without container wiring and remote configuration.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
ems/src/test/groovy/org/openremote/extension/ems/manager/gopacs/GOPACSHandlerTest.groovy |
New Spock spec with signed-message fixtures and assertions for day-ahead GOPACS/UFTP flows. |
ems/src/main/java/org/openremote/extension/ems/manager/gopacs/GOPACSHandler.java |
Adds a test-support constructor to instantiate the handler with injected services/executor/private key and without deployment/remote config. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| this.client = null; | ||
| this.gopacsAddressBookResource = null; | ||
| this.gopacsAuthResource = null; | ||
| this.gopacsServerResource = null; | ||
|
|
There was a problem hiding this comment.
This path already degrades gracefully — no NPE is thrown.
-
fetchBearerToken()wraps thegopacsAuthResourcecall in try/catch (Exception e). A nullgopacsAuthResourceraises an NPE, which is caught and the method returns"". -
getParticipantInformation()checks the blank token before touching the address book:
String authorization = fetchBearerToken();
if (authorization.isBlank()) {
LOG.warning("Skipping participant lookup for " + domain + ": no OAuth2 bearer token available");
return Optional.empty();
}
try (Response response = gopacsAddressBookResource.fetchParticipantByDomain(authorization, domain)) {So even with participants unseeded: caught NPE → blank token → Optional.empty(), and gopacsAddressBookResource is never dereferenced. Additionally, the covered flows pre-seed participants, so the participants.containsKey(domain) cache returns first and fetchBearerToken() is not called at all.
Leaving the constructor as-is; no-op resource implementations would be unused plumbing.
Summary
Adds test coverage for the
GOPACSHandlerday-ahead capacity-steering message flow on the AGR (EMS) side, closing the gap left by the UFTP V2→V3 participant migration (#40). Theemsmodule previously had no tests for the GOPACS handler.The spec drives real signed UFTP messages through the handler's actual entry point (
processRawMessage) using libsodium crypto — no database, no container, no network. Inbound payloads are embedded as XML fixtures matching the real wire format (DSOnilsgrid.net→ AGRopenremote.io, v3.0.0, attribute-style). A small test-support constructor onGOPACSHandlerskips remote config (OAuth client / private-key file) and JAX-RS deployment; aRecordingGOPACSHandlersubclass captures outbound messages (both the library-generated responses and the handler-builtFlexOffer); scheduled work runs inline for deterministic assertions.Covered flows:
powerMaximumFlexRequest= importMax,powerMinimumFlexRequest= exportMax); replies withFlexRequestResponse(Accepted) thenFlexOffer. The emittedFlexRequestResponseis asserted to match the reference message shape (result, referenced request id, swapped domains, version, conversation id).currentPowerFlexRequest, plus the offtakepowerLimitMaximumProfileFlexOrder/ feed-inpowerLimitMinimumProfileFlexOrderprofile); replies withFlexOrderResponse(Accepted).CongestionPointdiffers from the contracted EAN is dropped: no asset mutation, no reply (the V3 re-scoping).