fix(gateway): frame a component's loss-of-comms fault from the apps it hosts - #681
Draft
bburda wants to merge 4 commits into
Draft
fix(gateway): frame a component's loss-of-comms fault from the apps it hosts#681bburda wants to merge 4 commits into
bburda wants to merge 4 commits into
Conversation
…t hosts A protocol bridge reports PLC_COMMS_LOST under the PLC runtime component, and a component holds no data values of its own: it exports no DataProvider, and the x-plc-data route answers for apps only. The fault detail therefore carried a rosbag and no freeze_frame at all, on the confirm edge and after a restart, while the apps that component hosts kept serving the last row they read before the link died. EntityFreezeFrameCapture now falls back to the entities a reporting source hosts when that source read nothing itself, one freeze_frame entry per hosted app, named after the app. The gateway resolves them through faults::resolve_entity_source_fqns, the same helper /components/<id>/faults scopes by, so the frames come from exactly the sources that endpoint attributes to the component. The component itself gets no entry, there is nothing on it to read. A component that serves its own values is unchanged, and so is every app fault. Adds a docker scenario that writes a distinctive value, kills the OPC-UA server, and asserts the component's fault detail carries that value in a frame named after the hosted app. Stacks on fix/opcua-rescan-comms-lost-freeze-source (PR #660), which touches the same file.
The tutorial promised that a hosted-app entry carries connected: false and source_timestamp. On the shipped path it carries neither. An app with node-map entries is data-bearing, so the gateway resolves the plugin's DataProvider for it, and OpcuaPlugin::list_data returns items and nothing else. The link flag and the timestamp are added by the x-plc-data route, which the provider path never consults. The API reference already stated the conditional form, so the two documents disagreed. Both now say the same thing: the two fields ride a frame only when the plugin's payload reports them, a frame read through a DataProvider names source and captured_at and need not carry either, and the OPC UA plugin's list_data reports neither today. The reference also gains the naming rule a component's frames follow, and the plugin changelog gains the behaviour entry. Pinned by a unit test in the shipped shape: providers for the hosted apps, none for the component, a route fetcher that would report connected: false if consulted, and the assertion that the frames name the provider path and carry no link flag. The route-path test keeps its coverage under a name that says which path it exercises, which is what let the wrong sentence through. Adding connected and source_timestamp to list_data is deliberately not done here: that payload is read by every list_data consumer.
… it lives The scenario was invoked by nothing: not the plugin workflow, not test_all.sh, not the README. A regression it would catch had no standing guard and no discoverable entry point. It now runs in the alarm job, right after the alarm suite, which builds the same two images from the same Dockerfile, so the scenario's build is a cache hit rather than a second cold build. That job's failure dump learns the two container names. The README gains the invocation next to the discovery-race one. Corrects the reason the other suites cannot see this case, which the script's own header had wrong: the alarm suite does stop its server once, for the reconnect check. What none of the suites here do is read a fault's environment_data, so a detail that lost its freeze-frame looks exactly like one that kept it. Not added to test_all.sh, which does not carry the alarm suite either.
"One entry per hosted app" is false for an App that exists only to host alarm events. An event_alarms entry, and the auto_alarms fallback App, is registered under the component but owns no node-map entries, so has_data() is false, no DataProvider resolves for it, and its x-plc-data route answers 404. The engine is right to skip it, there is nothing to read. The three sentences describing the behaviour were not: the API reference, the tutorial and this plugin's changelog now all say one entry per hosted app that has values to read, and name the alarm-only app as the case that yields none. Pinned by a unit test in the shipped shape: a data-bearing hosted app with a provider, an alarm-only one with no provider whose route answers nothing, and the assertion that exactly one frame comes back, named after the app that had values. The alarm-only app's read is counted so the test cannot pass by never reaching it. The README paragraph also reasoned about the wrong two suites. It now names the two this file actually documents: the OpenPLC one keeps its server up for the whole run, the discovery race does take its server away but asserts on what discovery names the component. Neither reads a fault's environment_data.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A
PLC_COMMS_LOSTfault reported by a plugin-backed component carried a rosbag and no freeze frame. A component holds no data of its own: noDataProvider, andx-plc-dataanswers for apps only. The apps it hosts kept serving the last row read before the link died.The capture now descends into the entities a reporting source hosts when the source yields nothing: one frame per hosted app that has values to read, named after the app, with
x-medkit.source. An alarm-only app contributes no entry, and the component gets none. A component with its own provider keeps its single frame. App faults are unchanged. The hosting relation comes fromfaults::resolve_entity_source_fqns, the resolver/components/<id>/faultsuses.The tutorial and the REST reference now say what a plugin-backed frame carries:
sourceandcaptured_atalways,connected: falseandsource_timestamponly when the plugin's payload reports them. The OPC UA plugin's data provider reports neither, so its frames carry the last known values withoutconnected: false. That is a separate item on the plugin.Stacked on #660 and #680, which touch the same file.
Issue
Type
Testing
Five unit tests in
test_entity_freeze_frame_capture.cpp: hosted apps read through their providers (two frames, no link flag), one data-bearing and one alarm-only app (one frame), hosted apps read through the route, a component with its own provider (one frame, with a positive control), and an app fault (one frame).New scenario
run_comms_lost_frame_test.sh: writes a value, kills the OPC UA server, asserts the component's fault carries a frame named after the hosted app holding that value. Passes on this branch, fails on the base with"snapshots": []. It runs in the plugin's alarm CI job and is documented in the plugin README.test_all.sh18/18, alarm and discovery suites green. Gateway suite: 3955 tests, 0 failures on the stacked tree.Checklist