mirror of
https://github.com/OPCFoundation/UA-.NETStandard.git
synced 2026-10-28 22:55:49 +08:00
aas
4
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b17007bd55 |
Stop the encoder tests flooding the VSTest channel with per-test output (#4219)
# Description The `Core.Encoders` test job of run [`31249610490`](https://github.com/OPCFoundation/UA-.NETStandard/actions/runs/31249610490) printed nothing for 57 minutes and was killed by the 60-minute job timeout. Issue #4213 recorded that as "hung at or before the first test" — that reading was wrong, and the evidence to disprove it was already in the job's own artifact. The blame collector *had* written a hang dump and it *was* uploaded, inside the ordinary `dotnet-results-Core.Encoders-*` artifact (11 MB of it was the dump), where nobody looked for it. Opening it names the cause precisely. ## What the dump shows 522 threads (408 background) in a process that finishes in 25 seconds when healthy. Every test had already run; NUnit was in `OneTimeTearDown` waiting on its event pump: - the **event pump thread** is blocked in `NUnitEventListener.TestFinished` → `TestRunEventsHandler.HandleLogMessage` → `LengthPrefixCommunicationChannel.Send` → `Socket.Send`, on a socket that never drained. That send holds the channel's lock; - `TestRunCache.SendResults` is blocked on that channel lock, and it holds the cache lock; - `TestRunCache`'s **one-second timer** then fired repeatedly into that held cache lock, and the thread pool injected a fresh worker for each — **399 threads** parked in `Monitor.Enter_Slowpath` behind a single lock; - the NUnit run thread sits in `EventPump.Stop()` → `Thread.Join()`, so the run can never complete. ## What put the socket under that much pressure Volume of test output. Every encoder case dumps its input, its encoded payload and its decoded result, the NUnit adapter forwards each captured line to the runner as an individual message over that socket, and the suite has 2929 cases. This is not marginal: | | Before | After | | --- | --- | --- | | `Core.Encoders` TRX, green local run | **496 MB** | **4 MB** | | `Core.Encoders` published CI artifact | **156 MB** | ~3 MB | | Next-largest test job's artifact, for scale | 15 MB | 15 MB | | `Client.ComplexTypes` TRX | 74 MB | 40 MB | So the suite was shipping half a gigabyte of text through a socket, one message per line, on every run and on every OS — and paying for it in artifact storage even when nothing went wrong. ## The change `EncoderCommon` gains a buffered `TestOutput` writer. The dumps are collected per test and handed to `TestContext.Out` in `TearDown` **only when the test did not pass** — which is the only time anyone reads them. Nothing is lost: a failing test still reports its full input/encoded/decoded dump under *Standard Output Messages*, verified by injecting a deliberate failure. Explicit opt-ins (`PrettifyAndValidateJson(..., outputFormatted: true)`) and the static helpers keep writing immediately. The same base class is shared by the `Client.ComplexTypes` fixtures, so those are moved over too rather than left with half-buffered, half-immediate output. Two supporting changes: - **`.github/workflows/buildandtest.yml`** — `timeout-minutes: 30` on the `Test` step. The blame collector did its job here (dump at +50 min, once the run went quiet), but the run still had not unwound 7 minutes later when the *job* timeout cancelled everything, so the step needs a bound below the job's. `Upload test results` already runs `if: always()`, so the dump is still published. - **`docs/DeveloperGuide.md`** — a "Test output" convention under *Running tests*, so the next data-driven fixture does not re-introduce this. ## Notes for reviewers - `[Parallelizable]` on these fixtures is `ParallelScope.Self`, i.e. fixture-level; tests inside a fixture stay sequential, so the per-fixture buffer is as safe as the existing per-fixture `RandomSource`/`DataGenerator` state that is already reset in `SetUp`. - I separately confirmed that `--blame-hang-timeout` *does* fire on a hang before the first test (minimal NUnit repro, dump at exactly the configured timeout), which is what rules out the original "hung during startup/discovery" theory independently of the dump. - Local verification was scoped to the two affected suites rather than the whole solution: `Opc.Ua.Core.Encoders.Tests` 2929/2929 on **net10.0** *and* **net48**, `Opc.Ua.Client.ComplexTypes.Tests` 2773/2773 on net10.0, all building with 0 warnings. The full `UA.slnx` run is left to CI. ## Related Issues - Fixes #4213 ## Checklist - [x] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [ ] I have addressed **all** PR feedback received. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: da92151a-3da2-4caf-a39c-5556e56f0506 |
||
|
|
0383472ebc |
Fix PubSub occurrence publishing and JSON DataValue status encoding (#4106)
### Summary Three related gaps mean no `PublishedDataSet` can produce a message that is not a key frame or a derived delta frame. `PubSubDataSetMessageType.Event` and the `ua-event` wire tag of Part 14 §7.2.5.4 are modelled but unreachable. This PR also corrects the JSON `DataValue` status member to the Part 6 Table 42 name `Status`. ### 1. A dataset cannot declare what its sample is `PublishedDataSetSnapshot` carries a metadata version, fields and a timestamp. `WriterGroup.BuildDataSetMessageAsync` therefore decides the message kind alone: `KeyFrameCount <= 1` forces `KeyFrame`, otherwise it derives a delta by comparing the snapshot **positionally** against the previous one. That derivation assumes successive snapshots describe the same fields in the same order, which holds only for a source returning its complete current state every cycle. A source whose samples are *occurrences* — an event, a condition snapshot, or a delta it has already computed — cannot satisfy it: consecutive samples carry different fields, so field *i* of one occurrence is compared against field *i* of an unrelated earlier one, and `Math.Min` silently truncates when the counts differ. `PublishedDataSetSnapshot` now carries an optional `MessageType`. When set, the writer publishes exactly the supplied fields under the declared type and leaves its key-frame state untouched. When null — the default, and every existing caller — behaviour is unchanged. ### 2. The event writer was unreachable `EventDataSetWriter` and `EventPublishedDataSet` implement the Part 14 §6.2.4 event model correctly, but nothing could use them: - `EventPublishedDataSet` did not implement `IPublishedDataSet`, so `PubSubApplication` could not register an event dataset; - nothing in the library constructed `EventDataSetWriter`, and it was not an `IDataSetWriter`; - `WriterGroup` appends at most one message per writer per cycle, whereas an event writer produces one per occurrence. Now: `EventPublishedDataSet` is an `IPublishedDataSet` whose general `SampleAsync` drains one occurrence per cycle declared as an event; `EventDataSetWriter` is an `IDataSetWriter`; `PubSubApplication` builds an event dataset when the configured `DataSetSource` is a `PublishedEventsDataType` and the registered source is an `IEventSampler`; and a writer group drains every pending occurrence in one publish cycle. Event-writer sequence numbers now use the WriterGroup checkpoint state, so failover and restart resume above the shared checkpoint. The rows-returning `EventPublishedDataSet.SampleAsync` is renamed `SampleEventsAsync`, both to make room for the interface member and to match `IEventSampler.SampleEventsAsync`. ### 3. A metadata announcement hides its own payload `JsonMetaDataMessage` documents that the payload *"is exposed both on the base `PubSubNetworkMessage.MetaData` property and on `MetaDataPayload` so callers can use whichever accessor matches their fluent style."* `MetaDataPublisher` set only `MetaDataPayload`, so the documented contract was false: any consumer, transform or encoder hook reading the base property saw an announcement as a message carrying nothing. Both are now populated. Dataset subscriptions also use a dispose-safe subscribe/recheck handshake, preventing a concurrent shutdown from leaving a late handler attached. ### 4. JSON DataValue status used the wrong member name Part 6 section 5.4.2.18 Table 42 names the `DataValue` status member `Status`; `StatusCode` is its data type. `JsonEncoder` and `JsonDecoder` instead shared the member name `StatusCode`, so stack-to-stack round-trips passed while standards-conformant peers could not exchange non-Good status values. Both directions now use `Status`. The encoder regression test also verifies that `StatusCode` is absent from the emitted `DataValue` object. Fixes #4111. ### Compatibility The snapshot property is optional and defaults to null, so existing PubSub sources and current-state sampling behavior remain unchanged. The `EventPublishedDataSet.SampleAsync` rename is source-breaking on a type that could not previously be reached from the runtime. The JSON `DataValue` wire member intentionally changes from `StatusCode` to the specification-defined `Status`. No legacy alias is retained: the encoder emits `Status`, and the decoder expects `Status`. ### Testing `Opc.Ua.PubSub.Tests` on `net10.0`: 1341 passed, 1 skipped, 0 failed. New coverage: - `WriterGroupDeclaredMessageTypeTests` — a declared type is honoured, declared samples never become delta frames and are never suppressed as unchanged, and an undeclared source keeps the existing key-frame cadence. - `EventDataSetWriterTests.EventPublishedDataSet_SamplesOneOccurrencePerSnapshotAsync` — the general contract drains one occurrence per call, declares it as an event, and reports nothing when exhausted. - `WriterGroupEventWriterHotStandbyContinuesSequenceNumberFromSharedCheckpointAsync` — event messages share the checkpointed sequence state and continue monotonically after standby promotion. Issue #4111 validation: - `Opc.Ua.Types.Tests` JSON encoder/decoder fixtures on `net10.0`: 274 passed. - `Opc.Ua.Core.Encoders.Tests` JSON conformance cases on `net10.0`: 604 passed. - `Opc.Ua.PubSub.Tests` JSON fixtures on `net10.0`: 88 passed. - Targeted `net48` regression tests: 2 passed; core JSON conformance cases: 572 passed. - Review-feedback fixtures on `net48`: 11 passed. CI-fix validation: - `Opc.Ua.Core.Tests` on `net10.0`: 4145 passed, 86 skipped. - `Opc.Ua.Core.Tests` on `net48`: 4070 passed, 92 skipped. - Patch coverage check passes after adding targeted metadata and event publishing tests. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 1a300bc8-8bde-4a82-8fc3-476ef837bc6a Copilot-Session: 9f18bf87-795f-40a9-8494-b6e6334c4a97 |
||
|
|
84fa8e8906 |
CTT follow-up: monitored items, alarms, codecs, history, and model validation (#4002)
# Description Follow-up to #3978 based on the latest OPC UA CTT aggregate, matrix, Historical Access, Attribute, and Node Management runs. ## Aggregate run 16 - Ignore synthetic `BadBoundNotFound` raw-bound markers when feeding aggregate calculators. - Add direct and live historian regression coverage. ## Multi-dimensional Variant matrices - Fix `Variant.Copy()` so rank-2 Variant matrices preserve their payload and dimensions. - Enforce valid Variant matrix dimensions consistently across Binary, JSON, XML stream, and XML parser codecs. - Encoders return `BadEncodingError`; decoders return `BadDecodingError` for malformed matrix dimensions. - Add cross-codec valid/null/empty/malformed tests and a batched ReferenceServer Read regression. - Correct the previous CTT issue attribution: the invalid `Scalar_Static_Arrays2D_Variant` server encoding poisoned the batched CTT Read. ## Node Management AddNodes - Return `BadNodeIdRejected` for unsupported requested-NodeId namespaces. - Validate hierarchical ReferenceType source/target NodeClass constraints. - Document run-18 confirmation that all remaining 15 AddNodes errors are CTT project/script configuration issues. ## Historical Access and Attribute Services run 18 - Reject whitespace in `NumericRange` syntax with `BadIndexRangeInvalid`. - Add HistoryRead tests for operation-level invalid syntax and per-DataValue `BadIndexRangeNoData`. - Document CTT defects: - `012.js` expects `BadIndexRangeNoData` at the operation level instead of on returned DataValues; - `Err-012.js` uses a non-historizing node for an access-denied test; - generic Attribute array helpers omit NodeId[] and StatusCode[] conversion paths. ## Base Information model validation run 19 - Run the CTT main session as `sysadmin` over Basic256Sha256 SignAndEncrypt so SecurityAdmin RolePermissions and EncryptionRequired restrictions are both satisfied without weakening the server model. - Preserve predefined well-known NodeIds while making generated dynamic type and optional-child factories allocate compatible per-instance NodeIds, remap internal references, and update references from the owning subtree. - Materialize dynamic RoleType properties through generated helpers and keep role-child string NodeIds disjoint from numeric RoleManager root IDs. - Add net48/net10 regressions for generator output, NodeId allocation/reference remapping, DI mandatory children, dynamic roles, and low-privilege versus SecurityAdmin Browse visibility. - Document CTT defects for permission-unaware mandatory-child validation, the UA 1.04 reference model used against a UA 1.05 server, stale ServerDiagnostics cache, and the `ConformanceUnits` scalar/array mismatch. ## Related Issues - Follow-up to #3960 and #3978. ## Checklist - [x] I have signed the CLA and read the CONTRIBUTING document. - [x] Tests prove the fixes and improve coverage. - [x] Required CTT documentation is updated. - [x] Focused builds/tests introduce no warnings. - [x] Affected tests pass on .NET Framework and .NET 10. - [ ] CI and CodeQL are green. - [ ] All PR feedback is addressed. ## Latest CTT full run and A&C run 20 - Fix Monitor Value Change V2 `036.js`: an ambiguous `DataValue(StatusCode)` call encoded `BadIndexRangeNoData` as a Good value. - Prove all 19 configured matrix monitored items notify when the selected value actually changes; document the independent `042.js` script defects. - Rebase dynamic `CertificateExpired` / `TrustListOutOfDate` alarm roots and descendants, restore standard type declarations and ModellingRules, and expose the cross-node-manager references. - Deliver method-triggered events to every authorized Session, fixing the two-Session Confirm scenario. - Preserve locale-only `LocalizedText` values consistently across Binary, JSON, and XML and align Acknowledge/Confirm comment behavior and tests. - Document the remaining proven CTT defects for TransactionDiagnostics, SemanticChange, History `013`, PolicyId scope, A&C, durable subscriptions, and Subscription Minimum events. ## Base synchronization Merged `master` through `007cfaf90` (`#4010`, repository layout consolidation) and retained the matrix regression tests at their new `tests/` locations. ## Latest validation - Focused merged-tree tests pass on net10 and net48. - `Opc.Ua.Server` and `Quickstarts.Servers` Release builds complete with 0 warnings and 0 errors on net10 and net48. - The existing `DisableEnableViaTypeAndInstanceMethodNoEventsDuringDisabledAsync` timing test took its documented inconclusive timeout path after the layout merge; no test failure was reported. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: romanett <romanett98@gmail.com> |
||
|
|
7cec2d614d | Move repository files to the consolidated layout |