mirror of
https://github.com/OPCFoundation/UA-.NETStandard.git
synced 2026-10-23 18:39:26 +08:00
fix/encoder-stack-depth-json-flake
3 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
9b034f8291 |
Enable nullable reference types centrally; migrate all unset and annotations-only projects (#4700)
# Description Nullable reference types are now enabled once, in `common.props`, and every project in the repository builds warning-clean with them. **Configuration** - `<Nullable>enable</Nullable>` lives in `common.props`. All per-project `<Nullable>` settings are removed: 178 project files (enable, annotations, and the `disable` in the three Aot test projects). - 419 per-file `#nullable enable`/`restore` directives and the 4 `#nullable disable` directives are removed. - Kept on purpose: - The 5 `<auto-generated>` schema files (`UANodeSet.cs`, `UA Type Dictionary.cs`, `OPCBinarySchema.cs`, `SecuredApplication.cs`, `PInvokeHelper.cs`) keep `#nullable enable`. The compiler ignores the project setting in generated code, so the directive is required there. - `tests/Opc.Ua.Interop.LegacyPeer` keeps `disable`. It builds against the 1.5.378 packages and does not import the repository props. - `docs/DeveloperGuide.md` and `.github/copilot-instructions.md` now describe the central setting. **Migration** (the 43 unset and 13 annotations-only projects, roughly 10k diagnostics) - **Production code: annotated at the declarations.** Covers `tools/Opc.Ua.SourceGeneration.Core`, `src/Opc.Ua.Lds.Server` and the LDS sample. - Members, parameters and returns are nullable where null actually flows. - Null-check helpers carry `[NotNullWhen]` (`IsNull`, `IsValidXmlName`, `IsMethodTypeDesign`). - `CoreUtils.Format`, `Utils.Format`, `ITemplateWriter.WriteLine` take `params object?[]`. `Template.AddReplacement` takes `string?` (rendering already skips null replacements). - `IRegisteredServerStore.RegisterAsync` returns `Task<RegistrationEntry?>`: it returns null when a registration is removed. - Dereferences backed by an invariant (for example, the validated model) use `!`, so runtime behaviour is unchanged. - **Behavioural changes in production code** (small, deliberate): - `NodeSetToModelDesign` throws `InvalidOperationException` when the file is not a NodeSet. Before, it threw a NullReferenceException on the next line. - `ModelDesignValidator` starts its lookup tables empty instead of null. A redundant `if (m_nodes == null) return;` guard is gone. - **Test code: minimal annotations.** - `?` on values that can be null, `!` where the test asserts non-null. - `= null!` for fixture members assigned in SetUp. - `TryGetStructure<T>(out T? x)` where the inferred `T?` broke the `IEncodeable` constraint. - A few redundant `== null` checks on structs (`NodeId`, `ArrayOf<T>`) folded into the adjacent `IsNull`/`Count` checks. **Notes for reviewers** - The diff is large (~1,500 files) but almost entirely mechanical: `?`, `!` and directive removal. The non-annotation changes are listed above. - Known follow-up, not done here: `IModelDesign.Namespaces/TargetNamespace/NamespaceUris` stay non-nullable even though the validator returns null before it loads a dictionary. Making them nullable would ripple through every generator call site. ## Related Issues - Fixes #4439 ## Checklist - [ ] 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. - [ ] 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. The "no new warnings" box covers net10.0 and net48: full non-incremental builds of `UA.slnx`, `tools/SourceGeneration.slnx`, `tools/MigrationAnalyzer.slnx` and the Aot test projects finished with 0 warnings and 0 errors under the repository's warnings-as-errors settings. net9.0 and net8.0 also had no nullable diagnostics, but they were not rebuilt after the final fixes. Tests have not been run locally yet. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
37d8716a9b |
Fix Like filtering (GDS queries, ContentFilter), QueryServers paging and FindApplications found by the CTT GDS run (#4481)
Triage of the CTT **GDS** conformance group (CTT 1.05.06, scripts 1.05.513) against `ConsoleReferenceServer --ctt -a`, which hosts the GDS node manager. The baseline run had 60 errors in 4 CUs. This PR fixes the three server defects behind them and documents the rest in `plans/ctt-issues.md`. ## Server defects fixed | Defect | Spec | CTT tests fixed | | --- | --- | --- | | QueryServers/QueryApplications Like filters: the hand-written tokenizer in `ApplicationsDatabaseBase.Match` returned no records or all records for `%_erver%`, `%e_`, `%\_%`, `%\%%`, `%[q-s]`, `%[^q-s]`, `%_ompliance%`, and accepted the malformed `%[a^j-l]%` | Part 4 §7.7.3 Table 120 (whole-string match; "The ^ shall be the first character inside on the []"), Part 12 §6.5.10/§6.5.11 | Application Directory 062, 066, 068, 071, 073 (078 now returns `Bad_InvalidArgument`, see C22); Query Applications 013, 017, 018, 019, 022, 024 | | QueryServers used the application id as the `RecordId` of every DiscoveryUrl record, so `StartingRecordId` paging skipped the remaining DiscoveryUrls of an application | Part 12 §6.5.11 Table 15: one record per DiscoveryUrl | Application Directory 045, 075 | | FindApplications with an empty ApplicationUri returned every registered application | Part 12 §6.5.4: result size 0 or 1; `Bad_InvalidArgument` for an invalid URI | Application Directory 004 | Changes: - `Opc.Ua.LikePattern` (new, `Opc.Ua.Types`) parses, validates and matches Like patterns: `%`, `_`, `\`, `[list]`, ranges, `[^list]` and the legacy `[!list]`. The GDS database and `AliasNameWildcardMatcher` (FindAlias) both use it now. The alias matcher's previous regex translation also accepted `[a^j-l]`. - QueryServers/QueryApplications reject a malformed filter with `Bad_InvalidArgument` and parse each filter once per call (`ValidateQueryServersArguments` / `ValidateQueryApplicationsArguments`). - FindApplications returns `Bad_InvalidArgument` for an empty or blank ApplicationUri. Other unknown strings, including non-URIs, return an empty array: CTT `003.js` calls it with up to MaxStringLength `X` characters and expects Good, and §6.5.4 allows both readings. - `QueryApplications` compared `(int)startingRecordId`, so a StartingRecordId above `int.MaxValue` returned every record. - Every DiscoveryUrl record (`ServerEndpoint`) now has its own monotonically increasing ID, persisted in the JSON database. `JsonApplicationsDatabase.Load` assigns and saves IDs for databases written before this change. A note on 074.js and Query Applications 025.js: both passed before and fail now. Their patterns `%[^f-h]%` / `%[^w-y]%` expect "contains none of f–h", which no Like pattern can express. The old matcher special-cased `[^`, and that quirk is why they passed (C21). ## ContentFilter Like operator `FilterEvaluator` had its own regex translation of Like patterns with the same class of defects: the regex was not anchored (`abc` matched `xxabcxx`), `^` was escaped so the 1.05 negated list `[^13-5]` never worked, and malformed patterns threw from `Regex`. - The Like operator now uses `LikePattern`. An invalid search string matches nothing, so Like resolves to FALSE, as Part 4 §7.7.3 specifies for an operand that cannot be resolved to a string. - `ContentFilterElement.Validate` rejects a malformed **literal** Like pattern with `Bad_FilterOperandInvalid` for that operand (`Bad_ContentFilterInvalid` for the element), so an event filter with such a pattern is refused when the monitored item is created. Patterns from other operands (for example an AttributeOperand) are only known at evaluation time and evaluate to FALSE. - The regex helpers are removed. No other code in the repository uses `FilterOperator.Like`, and the existing Like tests already assumed whole-string matching. ## Classification of the remaining failures | Test | Classification | Entry | | --- | --- | --- | | Application Directory 060, 067, 069 | CTT: registers an ApplicationUri containing a raw `%` / `\`, which is not a valid URI | C19 | | Application Directory 065, 060; Query Applications 011, 016 | CTT: `[_]` / `[%]` evaluated as "contains" | C20 | | Application Directory 074; Query Applications 025 | CTT: `%[^x-y]%` evaluated as "contains none of" | C21 | | Application Directory 079, 078 | CTT: `MethodCalls.js:286` reads the output arguments of a failed call (078 now gets the correct `Bad_InvalidArgument` and hits this) | C22 | | Application Directory 018 | CTT: selects `ActionTimestamp` (BrowseName is `ActionTimeStamp`); the missing event is the queue size issue fixed by #4480 | C23 | | Application Directory 019 | CTT client: the batched RegisterApplication Call never reaches the server (no server log entry, no service fault); new test shows the server handles the batch | C24 | | Application Directory 010 | CTT: dereferences the ApplicationId of a `Bad_EntryExists` result | C25 | | Application Directory 012 step 5, 032 | CTT: requires ServerCapabilities for a Server; Part 12 has no such rule | C26 | | Application Directory 027 | CTT: updates a Server with an `opc.tcp` DiscoveryUrl to a Client (invalid per Part 12 §6.5.5, Part 4 §7.2) | C27 | | Application Directory 029, 038, 039 | CTT: expects `Bad_InvalidArgument` where Part 12 defines `Bad_NotFound` | C28 | | Application Directory 005 | CTT: expects `Bad_InvalidArgument` for a string above MaxStringLength, which cannot be decoded | C29 | | Query Applications 036 | CTT: expects `rcp+` URLs it never registered | C30 | | Query Applications 038 step 5 | CTT: applicationType is a mask, `3` = Servers \| Clients is valid (step 6, max UInt32, already returns `Bad_InvalidArgument`) | C31 | | AliasName Discovery 001, 002, 004 | Not applicable: GDS AliasName Server Facet (Part 17 Annex C) is not implemented; 001 also sees the reference server's own aliases | config notes | | AliasName Discovery 005–015, LDS-ME Connectivity | Configuration (AliasName sources / registered LDS) | config notes | Which server to target: Application Directory and Query Applications run the same `Opc.Ua.Gds.Server` code on the reference server (in-memory database, clean on every start) and on a dedicated GDS. The dedicated GDS sample keeps a JSON database, and leftover records of earlier runs change every expected record count. The GDS AliasName Discovery CU needs a GDS that implements the facet and should be deselected on both. Spec conflict, server unchanged: Part 12 §6.5.10/§6.5.11 say QueryApplications/QueryServers *"shall not return records with a ServerCapabilities that includes NA"*, but the CTT registers its reference Servers with `NA` and expects them in the results. ## Tests - `LikePatternTests` (Types): Part 4 Table 120 examples, CTT patterns, invalid patterns (93 cases). - `LinqApplicationsDatabaseTests`: paging over multi-URL applications, RecordId after update, JSON reload and legacy databases, CTT filters for QueryServers and QueryApplications, StartingRecordId above `int.MaxValue`, empty FindApplications. - `ApplicationsDatabaseBaseTests`: CTT patterns, invalid filters rejected. - `GdsApplicationDirectoryTests` (live): invalid pattern → `Bad_InvalidArgument` with no output arguments; four RegisterApplication operations in one Call. - `GdsDepthTests.AppDirFindApplicationsEmptyUriAsync` expects `Bad_InvalidArgument`; `AppDirFindApplicationsUnknownNonUriReturnsEmptyAsync` covers the 003.js strings. - `FilterEvaluatorTests` (Core): the Part 4 Table 120 examples through the ContentFilter, whole-string and case-sensitive matching, invalid patterns evaluating to FALSE, and validation of literal patterns (44 cases). ## CTT rerun Same GDS selection, fresh `ConsoleReferenceServer --ctt -a` built from this branch: **47 errors (baseline 60)**. - Now pass: Application Directory 004, 045, 062, 066, 068, 071, 073, 075; Query Applications 013, 017, 018, 019, 022, 024 (15 errors gone). - Newly fail as expected: Application Directory 074 and Query Applications 025 (C21). - 078 changed from "Good instead of BadInvalidArgument" to the C22 helper abort. - All remaining errors match C19–C31 or the AliasName Discovery note. - Rerun on `4e4fb7f7c` (review fixes, ContentFilter change, lenient FindApplications for non-URI strings): 48 errors. It matches the 47-error run exactly, plus `028.js` missing its audit event (QueueSize 1 flakiness, see C23 / #4480). An intermediate build that rejected every non-URI in FindApplications broke `003.js`, which is why that check was relaxed again. - Patched-script run (recommended fixes of C19, C20, C22, C23, C25, C29 applied to a scratch copy of the CTT project): 41 errors. `010`, `060`, `065`, `067`, `078`, `079`, QA `011`, `016` pass; `018` receives a correct audit event (the validator then trips over another script bug); `005` gets the expected `Bad_EncodingLimitsExceeded` ServiceFault. No further GDS server defect showed up. That ServiceFault carries RequestHandle 0 (Part 4 §7.33 says it *should* be echoed), a transport-level item left for a separate change. - AliasName group (FindAlias uses `LikePattern` now): 1 error, the known CTT defect in `AliasName Hierarchy/002.js`, unchanged. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
7cec2d614d | Move repository files to the consolidated layout |