[WotCon] Add the WoT Connectivity registry and its stores - #4146
[WotCon] Add the WoT Connectivity registry and its stores#4146marcschier wants to merge 27 commits into
Conversation
Adds a stable, injectable registry for Thing Description and Thing Model documents, with in-memory and file-backed stores behind one interface. The file-backed store commits atomically: content-addressed blobs are verified and skipped rather than rewritten, blob writes are staged under a temporary name and published in a single indivisible step through the file-system atomic-replace capability, and a commit that is interrupted leaves either the previous state or the new one, never a partially written blob that the manifest already references. Recovery artefacts left by an interrupted commit are detected and rolled back on load. Documents are versioned with epochs and desired/active state, labels and bounds are persisted, and blob storage is delegated to the shared xRegistry resource store contract rather than reimplemented. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9e6a5abf-3299-4cd1-9855-010fedbf0ad8
The fluent builder generator emits calls to INodeManagerBuilder.VariableFromDataTypeId and to a NodeManagerBuilder constructor overload that carries the data-type lookup, but the runtime side of that API was missing, so every generated node manager failed to compile with CS1729 and CS1061. Adds the VariableFromDataTypeId resolution to the builder interface and implementation, along with NodeStateLookupExtensions.FindByDataType, which is the lookup the builder delegates to and has no other consumer. Resolution reports BadNodeIdInvalid for a null data type, BadNodeIdUnknown when nothing matches, BadBrowseNameDuplicated when the match is ambiguous, and BadTypeMismatch when the resolved node is not a variable. An optional browse name disambiguates a data type that is carried by more than one variable. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9e6a5abf-3299-4cd1-9855-010fedbf0ad8
|
Fixed the net10.0 solution build failure on this PR. This branch carries the The fix lands in #4132 (where the generator change belongs) and is cherry-picked here so Verified locally: |
DiNodeManager constructed NodeManagerBuilder without the data-type resolver, so
VariableFromDataTypeId reported BadNodeIdUnknown ("no predefined variable has DataType")
for every DI node manager - a misleading error, since the lookup had simply never
been supplied rather than the variable being absent.
Delegates to NodeStateLookupExtensions.FindByDataType rather than hand-rolling the
scan a fourth time in this file.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 9e6a5abf-3299-4cd1-9855-010fedbf0ad8
…-registry # Conflicts: # src/Opc.Ua.Di.Server/DiNodeManager.cs # src/Opc.Ua.WotCon.Server/WotConModelPartition.cs # src/Opc.Ua.WotCon.Server/WotConnectivityNodeManager.cs
An empty collection expression binds to ImmutableDictionary<TKey, TValue> only on the newer framework, so the registry model compiled on net10.0 but failed on net48 with CS1729 and CS0019. Naming the Empty singleton explicitly works on every target and matches how the labels defaults are already written. The ImmutableArray collection expressions elsewhere in the registry are unaffected and keep their existing form. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9e6a5abf-3299-4cd1-9855-010fedbf0ad8
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9e6a5abf-3299-4cd1-9855-010fedbf0ad8
Linearising the stack brought the registry together with the core-types change that moved atomic replacement onto IFileSystem itself. The registry still carried the superseded IAtomicFileReplace capability interface, so both designs were present at once. Deletes IAtomicFileReplace and migrates its users to IFileSystem.Replace. The blob store no longer probes for the capability, because every file system now provides it, and the test that asserted the failure path for a file system without the capability is removed with it - that state is no longer representable. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9e6a5abf-3299-4cd1-9855-010fedbf0ad8
There was a problem hiding this comment.
Pull request overview
Adds the WoT Connectivity (WoT-Con) registry surface to Opc.Ua.WotCon.Server, including an injectable registry service model and document stores (in-memory and file-backed via an xRegistry IXRegistryResourceStore abstraction), plus a comprehensive new test suite validating CRUD, labels, persistence, and OPC UA FileType file-handle behavior.
Changes:
- Introduces the registry domain model + bounds/validation helpers (
WotRegistryModel,WotRegistryPersistenceBounds,WotLabelValidator) and injectable service/store contracts (IWotRegistryService,IWotRegistryStore). - Adds document storage implementations, including a content-addressed blob store behind
IXRegistryResourceStore(WotBlobResourceStore) and a generalized per-resource FileType manager (WotResourceFileManager). - Adds extensive NUnit coverage for store contracts, transactional commit outcomes, FileType behavior, labels/ordering, and file-store reload behavior.
Reviewed changes
Copilot reviewed 26 out of 26 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/Opc.Ua.WotCon.Tests/TestMaterialization.cs | Shared TD/TM/invalid JSON builders used across registry/materialization tests. |
| tests/Opc.Ua.WotCon.Tests/Registry/XRegistryResourceStoreContractTests.cs | Shared contract test suite for IXRegistryResourceStore implementations. |
| tests/Opc.Ua.WotCon.Tests/Registry/WotResourceFileManagerTests.cs | Unit tests for the new WotResourceFileManager FileType behavior (handles, auth, bounds, commit). |
| tests/Opc.Ua.WotCon.Tests/Registry/WotRegistryTransactionTests.cs | Fault-injection tests for transactional commit outcomes and service publish semantics. |
| tests/Opc.Ua.WotCon.Tests/Registry/WotRegistryServiceTests.cs | Core CRUD/versioning/state tests for WotRegistryService. |
| tests/Opc.Ua.WotCon.Tests/Registry/WotRegistryServiceExtendedTests.cs | Additional coverage for group helpers, slug/normalize paths, and registry/group label APIs. |
| tests/Opc.Ua.WotCon.Tests/Registry/WotRegistryServiceCrudTests.cs | Tests for xRegistry CRUD methods used by UA management methods (group/resource create/delete, validate). |
| tests/Opc.Ua.WotCon.Tests/Registry/WotRegistryModelTests.cs | Value-object tests for digest/version/labels model types. |
| tests/Opc.Ua.WotCon.Tests/Registry/WotRegistryLabelsServiceTests.cs | Label/attribute service tests (validation, bounds, ordering, persistence). |
| tests/Opc.Ua.WotCon.Tests/Registry/WotBlobResourceStoreTests.cs | Runs the shared store contract against WotBlobResourceStore and validates on-disk layout expectations. |
| tests/Opc.Ua.WotCon.Tests/Registry/FileWotRegistryStoreExtendedTests.cs | File-store error-path and persistence regression coverage (manifest/blob/labels). |
| src/Opc.Ua.WotCon.Server/WotConnectivityNodeManager.cs | Updates method handler result types to match source-generated method state result types. |
| src/Opc.Ua.WotCon.Server/Registry/WotResourceFileManager.cs | New generalized FileType manager for registry document nodes (read snapshot, buffered write, commit-on-close). |
| src/Opc.Ua.WotCon.Server/Registry/WotRegistryPersistenceBounds.cs | New bounds object enforcing caps for documents, groups/resources, labels, etc. |
| src/Opc.Ua.WotCon.Server/Registry/WotRegistryModel.cs | New immutable snapshot model for registry/groups/resources/versions + digest and label ordering helpers. |
| src/Opc.Ua.WotCon.Server/Registry/WotLabelValidator.cs | Key/value validation for xRegistry labels prior to materialization into browseable nodes. |
| src/Opc.Ua.WotCon.Server/Registry/WotBlobResourceStore.cs | New IXRegistryResourceStore implementation using content-addressed blob files with atomic replace. |
| src/Opc.Ua.WotCon.Server/Registry/IWotRegistryStore.cs | Defines transactional commit contract + explicit commit outcome exceptions for external stores. |
| src/Opc.Ua.WotCon.Server/Registry/IWotRegistryService.cs | Defines the stable, injectable registry service API and DTOs/event args. |
| src/Opc.Ua.WotCon.Server/Registry/InMemoryWotRegistryStore.cs | In-memory implementation of the transactional store contract for tests/startup-seeded deployments. |
| src/Opc.Ua.WotCon.Server/Opc.Ua.WotCon.Server.csproj | Adds reference to Opc.Ua.XRegistry.Server. |
| src/Opc.Ua.WotCon.Server/Assets/WotAssetFileManager.cs | Updates handler delegate type to the source-generated method handler type. |
| src/Opc.Ua.Types/Utils/FileSystem/VirtualFileSystem.cs | Improves Replace atomic publish behavior using AddOrUpdate while preserving “no partial publish” semantics. |
Suppressed comments (3)
tests/Opc.Ua.WotCon.Tests/Registry/XRegistryResourceStoreContractTests.cs:128
Assert.Multiple(async () => ...)becomes an async-void lambda and can hide assertion failures. Capture the awaited values before enteringAssert.Multipleand keep the delegate synchronous.
Assert.Multiple(async () =>
{
Assert.That(document.Span.ToArray(),
Is.EqualTo(new byte[] { 0x01, 0xAA, 0xBB, 0x04 }));
Assert.That(await store.GetLengthAsync("a").ConfigureAwait(false), Is.EqualTo(4),
tests/Opc.Ua.WotCon.Tests/Registry/XRegistryResourceStoreContractTests.cs:172
Assert.Multiple(async () => ...)uses an async-void delegate, so the awaitedReadAsyncand the asserts may run outside the test body. AwaitReadAsyncfirst, then assert synchronously insideAssert.Multiple.
Assert.Multiple(async () =>
{
Assert.That(removed, Is.True);
Assert.That(again, Is.False, "Deleting an absent key is a no-op, not a fault.");
Assert.That(
tests/Opc.Ua.WotCon.Tests/Registry/XRegistryResourceStoreContractTests.cs:189
Assert.Multiple(async () => ...)is async-void under NUnit and can drop failures from awaited reads. Await the reads first and then assert synchronously.
Assert.Multiple(async () =>
{
Assert.That(
(await store.ReadAsync("a", 0, 16).ConfigureAwait(false)).Span.ToArray(),
Is.EqualTo(new byte[] { 0x01 }));
…istry # Conflicts: # src/Opc.Ua.WotCon.Server/Assets/WotAssetFileManager.cs
Tighten registry blob and file-handle bounds, reset file manager disposal state, and remove sync-over-async in affected tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9e6a5abf-3299-4cd1-9855-010fedbf0ad8
…o marcschier/wot-13-registry
…o marcschier/wot-13-registry
…o marcschier/wot-13-registry
…o marcschier/wot-13-registry
…o marcschier/wot-13-registry
…o marcschier/wot-13-registry
…o marcschier/wot-13-registry
…o marcschier/wot-13-registry
…o marcschier/wot-13-registry
…o marcschier/wot-13-registry
…o marcschier/wot-13-registry
Adds the WoT Connectivity registry service and stores for Thing Description and Thing Model documents.
This is PR 13 of the stacked split of integration PR #4093 and is stacked on #4140 (
marcschier/wot-11-bindings-core). The materialization runtime that consumes this registry follows separately.The registry has no dependency on the binding runtime or the NodeManager lifecycle; the stacking is only because this change shares the WoT Connectivity server project file with the preceding PRs.
Validation:
dotnet build src\Opc.Ua.WotCon.Server\Opc.Ua.WotCon.Server.csproj -c Release -f net10.0 -v:mdotnet build tests\Opc.Ua.WotCon.Tests\Opc.Ua.WotCon.Tests.csproj -c Release -p:CustomTestTarget=net10.0 -v:mdotnet test tests\Opc.Ua.WotCon.Tests\Opc.Ua.WotCon.Tests.csproj -c Release -p:CustomTestTarget=net10.0 --no-build -v:qdotnet build src\Opc.Ua.WotCon.Server\Opc.Ua.WotCon.Server.csproj -c Release -v:m