Skip to content

Releases: php-opcua/uanetstandard-test-suite

v1.5.2

Choose a tag to compare

@GianfriAurGianfriAur released this 10 Jun 10:40
b781409

v1.5.2 - 2026-06-10

Fixed ? Custom DataType nodes (ExtensionObjectsBuilder)

  • DataTypeDefinition attribute now exposed on TestPointXYZ (ns=3;i=3000) and TestRangeStruct (ns=3;i=3001) ? each DataTypeState carries a StructureDefinition (X/Y/Z and Low/High/Value, all Double scalars, DefaultEncodingId pointing at the respective Default Binary node). Previously reading attribute 23 returned Bad_AttributeIdInvalid, so OPC UA 1.04+ clients could not discover the structure layout. Used by the strengthened discoverDataTypes() integration tests in php-opcua/opcua-client.
  • Encoding nodes linked via HasEncoding (i=38) instead of HasComponent ? AddChild produced a non-conformant HasComponent reference, so spec-compliant clients browsing for HasEncoding could not find the Default Binary nodes (ns=3;i=3010 / ns=3;i=3011).

v1.5.1

Choose a tag to compare

@GianfriAurGianfriAur released this 10 Jun 10:39
dd82809

v1.5.1 ? 2026-06-04

Fixed - Container readiness / healthcheck

  • --health now gates on a real readiness marker instead of unconditionally returning 0. TestServerApp.OnServerStarted writes /tmp/opcua-ready only once the server reaches the Running state and its endpoints accept requests; dotnet TestServer.dll --health returns exit 1 until that file exists. Previously the healthcheck returned 0 immediately, so docker compose up --wait reported the container healthy during the server boot window ? the first client connects could race initialization and receive a top-level ServiceFault BadServerHalted (0x800E0000). This affected fast-connecting integration suites such as php-opcua/opcua-client-ext-reverse-connect, whose first two tests connected within ~1s of the (premature) healthy signal.
  • Stale marker cleared on boot ? Program.cs deletes any leftover /tmp/opcua-ready before starting, so a restarted container (restart: unless-stopped) is never reported healthy prematurely.

v1.5.0

Choose a tag to compare

@GianfriAurGianfriAur released this 27 May 11:58
0a20adc

v1.5.0 — 2026-05-27

Added — HTTPS Binary endpoint (Part 6 §7.4.4)

  • opcua-https-binary docker-compose service — exposes both opc.tcp://0.0.0.0:4862/UA/TestServer (internal) and opc.https://0.0.0.0:4852/UA/TestServer (host-mapped) on the same TestServer process. Used by the integration suite of php-opcua/opcua-client-ext-transport-https.
  • OPCFoundation.NetStandard.Opc.Ua.Bindings.Https v1.5.378.134 added to TestServer.csproj — provides the HttpsTransportListener UA-.NETStandard wires for opc.https:// endpoints.
  • EnableHttps / HttpsPort in ServerConfig.cs (default false / 4852), env-driven via OPCUA_ENABLE_HTTPS and OPCUA_HTTPS_PORT. When enabled, BuildBaseAddresses(config) appends the opc.https://0.0.0.0:{HttpsPort}{ResourcePath} URI to the BaseAddresses collection.
  • ServerConfiguration.HttpsMutualTls = false — plain TLS (no client cert) is accepted on CreateSession. Production deployments should keep mTLS on; the test endpoint flips it off so the PHP client can connect without a TLS client cert.
  • OPCUA_AUTH_USERS=true on the opcua-https-binary service. UA-.NETStandard's HttpsServiceHost filters the Anonymous user token policy out of the HTTPS endpoint description whenever HttpsMutualTls = false, so the endpoint must advertise at least one non-anonymous policy. The HTTPS integration test connects with seeded admin / admin123 credentials.
  • Pre-generated RSA 2048 HTTPS server certificate under certs/https-server/ (CN HttpsBinaryServer, SAN localhost + 127.0.0.1 + host.docker.internal + 0.0.0.0, EKU serverAuth, clientAuth). UA-.NETStandard's auto-generated application certificate defaults to 1024-bit RSA which modern TLS 1.2/1.3 rejects — scripts/generate-certs.sh now produces the stronger cert and Program.cs::InstallPregeneratedHttpsCertificate(config) copies it into /tmp/pki/own/ with the expected <CN> [<thumbprint>].der / .pfx filename layout, computed dynamically via X509Certificate2.Thumbprint.

v1.4.0

Choose a tag to compare

@GianfriAurGianfriAur released this 26 May 20:31
53eb3c2

v1.4.0 — 2026-05-26

Added — Reverse Connect (Part 6 §7.1.2.3) test methods

  • TestServerApp base class changed from StandardServer to ReverseConnectServer so the server-side ReverseConnectManager (UA-.NETStandard Opc.Ua.Server.ReverseConnectServer.AddReverseConnection(Uri, …) / RemoveReverseConnection(Uri)) is available at runtime. No behaviour change for the existing services — reverse connections are inert until a target is registered.
  • ReverseConnectMethodsBuilder under src/TestServer/AddressSpace/ — opt-in via the new EnableReverseConnect config flag (default true). Adds a TestServer/ReverseConnect folder with two Method nodes:
    • ns=2;s=TestServer/ReverseConnect/StartReverseConnect(host: String, port: UInt16) → status: StatusCode — calls AddReverseConnection(new Uri("opc.tcp://{host}:{port}")); idempotent against double-add (treated as Good).
    • ns=2;s=TestServer/ReverseConnect/StopReverseConnect(host: String, port: UInt16) → status: StatusCode — calls RemoveReverseConnection(...); returns BadNotFound if the URL was not registered, Good otherwise.
  • TestNodeManager signature extended with a fifth ctor argument TestServerApp testServer so the Method handlers can reach the server-side reverse-connect API through the cast-free path. Empty-host / zero-port inputs both yield BadInvalidArgument without touching the underlying manager.
  • Env-driven toggleOPCUA_ENABLE_REVERSE_CONNECT (default true). When disabled the TestServer/ReverseConnect folder is not built and the methods are absent.
  • Designed to drive the integration tests of php-opcua/opcua-client-ext-reverse-connect: the PHP client opens a listener on an ephemeral port, connects to the test server normally, calls StartReverseConnect("127.0.0.1", <port>), and the server dials out and emits a ReverseHello (RHE) toward the listener.

v1.3.0

Choose a tag to compare

@GianfriAurGianfriAur released this 26 May 06:37
55b02a5

v1.3.0 — 2026-05-26

Added — File Transfer (Part 5) fixtures

  • FileTransferBuilder under src/TestServer/AddressSpace/ — mirrors the existing builder pattern, self-contained, opt-in via the new EnableFileTransfer config flag (default true). Adds a TestServer/Files folder with six FileType nodes plus one FileDirectoryType:
    • ns=1;s=TestServer/Files/ReadOnlyFile — 1024 B, deterministic seed (MD5("readonly-seed") × 64), Writable=false, MimeType application/octet-stream
    • ns=1;s=TestServer/Files/EmptyFile — 0 B, Writable=false, MimeType text/plain
    • ns=1;s=TestServer/Files/LargeFile — 256 KB, bytes 0..255 repeated 1024 times, Writable=false (forces chunked Read against any sane negotiated max-message-size), MimeType application/octet-stream
    • ns=1;s=TestServer/Files/WritableFile — 0 B initial, Writable=true, the round-trip target for Open(Write)WriteClose → re-Open(Read) test patterns
    • ns=1;s=TestServer/Files/AppendableFile — 13 B initial ("seed-content\n"), Writable=true, the target for Open(Write | Append) semantics — the initial cursor sits at end-of-file
    • ns=1;s=TestServer/Files/ProtectedWritableFile — 0 B initial, Writable=true advertised but per-session Open(Write) checks the identity via UserManager: only the admin role obtains a write handle; anonymous, operator, and viewer receive Bad_UserAccessDenied. Open(Read) is allowed for every session
    • ns=1;s=TestServer/Files/RootDir — a FileDirectoryType with all four management methods wired (CreateDirectory, CreateFile, DeleteFileSystemObject, MoveOrCopy). Children are tracked in-process, addressable via the standard FileType/FileDirectoryType surface; MoveOrCopy supports both createCopy=true (clone) and createCopy=false (move)
  • InMemoryFileBackend — per-file MemoryStream-backed implementation. No disk I/O, no volumes, no cleanup setup. Every container restart resets all six files to their initial seed (and clears every runtime-created child of RootDir). Thread-safe via a single lock (UA-.NETStandard dispatches OnCall from its session worker pool, so concurrent handle access is real). Snapshot helper exposed for MoveOrCopy(createCopy=true).
  • Full OPC UA Part 5 §C method coverage wired on every FileType: Open(mode), Close(handle), Read(handle, length), Write(handle, data), GetPosition(handle), SetPosition(handle, position). Standard properties Size / Writable / UserWritable / OpenCount / MimeType populated; Size updated on every successful Write, OpenCount on every Open/Close.
  • Edge-case enforcementOpen(0)Bad_InvalidArgument, Open(Write) on a read-only file → Bad_NotWritable, Open(EraseExisting) without WriteBad_InvalidArgument, Read/Write on a handle missing the required mode bit → Bad_InvalidState, unknown fileHandleBad_InvalidArgument, Read past EOF → short-read (no error), Open(Write) on ProtectedWritableFile without admin role → Bad_UserAccessDenied, CreateDirectory/CreateFile with empty name → Bad_InvalidArgument, DeleteFileSystemObject / MoveOrCopy against an unknown NodeId → Bad_NodeIdUnknown.
  • TestNodeManager helpersAddNode(context, node) already exposed in earlier versions; new DeleteDynamicNode(nodeId) wrapper around the framework's internal DeleteNode to support the directory delete/move-out paths.
  • Env-driven toggleOPCUA_ENABLE_FILE_TRANSFER (default true). Disabling skips the entire TestServer/Files folder construction. On by default on every classic server.
  • Docs — new page docs/runtime-features/file-transfer.md covering NodeIds, initial content, Open mode matrix, round-trip / chunked-read test patterns, reset semantics, FileDirectoryType usage, and the per-user check on ProtectedWritableFile. Cascading updates in docs/index.md, docs/address-space/overview.md (now 10/11 top-level folders, new Files row in the tree), docs/reference/environment-variables.md, docs/server-instances/overview.md.

v1.2.0

Choose a tag to compare

@GianfriAurGianfriAur released this 22 Apr 08:00
f68e015

v1.2.0 — 2026-04-22

Added — Security Key Service (service 11, port 4851)

  • opcua-sks service — new classic OPC UA server instance that boots the shared TestServer image with OPCUA_ENABLE_SKS=true. Exposes the OPC UA Part 14 §8.4.2 GetSecurityKeys method under ns=1;s=TestServer/SecurityKeyService, letting PubSub subscriber-side clients (e.g. php-opcua/opcua-client-ext-pubsub's SksGroupKeyProvider) exercise the real RPC path against a live server instead of only MockClient.
  • SecurityKeyServiceBuilder under src/TestServer/AddressSpace/ — mirrors the existing builder pattern, self-contained, opt-in via EnableSks config flag so the other 10 server instances are unaffected.
  • Env-driven configOPCUA_ENABLE_SKS, OPCUA_SKS_GROUP_ID, OPCUA_SKS_POLICY_URI, OPCUA_SKS_TOKEN_ID, OPCUA_SKS_SIGNING_KEY_HEX, OPCUA_SKS_ENCRYPTING_KEY_HEX, OPCUA_SKS_KEY_NONCE_HEX, OPCUA_SKS_TIME_TO_NEXT_KEY_MS, OPCUA_SKS_KEY_LIFETIME_MS. All off by default on the other services; on only for the dedicated opcua-sks service.
  • Action updatesks is a new option for the servers CSV input in action.yml.
  • Docs — new section "11. Security Key Service" in docs/servers.md, new row in the endpoint table of docs/ci-integration.md, new row in README.md "What's Inside".
  • Test-only scope — hardcoded keys, no caller authentication, no rotation scheduling, no revocation. Real SKS deployments are expected to do all of the above.

Added — PubSub publisher (service 12, port 4850)

  • opcua-pubsub service — new UA-.NETStandard UDP+UADP publisher built from src/TestPublisher/ (separate Dockerfile Dockerfile.publisher, separate .csproj against the OPCFoundation.NetStandard.Opc.Ua.PubSub NuGet package). Broadcasts a deterministic DataSet (counter / timestamp / sine-value) every 500 ms, bringing real UADP interop coverage for Part 14 subscriber-side clients (e.g. php-opcua/opcua-client-ext-pubsub).
  • Env-driven configuration — same OPCUA_* prefix convention as the TestServer services. OPCUA_URL, OPCUA_NETWORK_INTERFACE, OPCUA_PUBLISHER_ID, OPCUA_WRITER_GROUP_ID, OPCUA_DATASET_WRITER_ID, OPCUA_DATASET_NAME, OPCUA_PUBLISH_INTERVAL_MS, OPCUA_TICK_INTERVAL_MS, OPCUA_LOG_LEVEL — one image, reconfigure via compose env.
  • Networking — publisher + opcua-pubsub-relay sidecar pair. Publisher sends unicast UADP to the relay on a shared compose bridge (pubsub-net); the relay forwards each datagram to host.docker.internal:14850. Subscribers on the physical host listen on 127.0.0.1:14850 (or 0.0.0.0:14850). Works identically on Docker Engine bare-metal (GitHub Actions runners, CI) and Docker Desktop (Linux / macOS / Windows) — multicast over the VM boundary is sidestepped entirely.
  • Security — unsecured (mode None). For signed and encrypted PubSub streams subscribers pair this with the opcua-sks service (service 11) — full end-to-end secured publisher + SKS is planned follow-up work.
  • Action updatepubsub is a new option for the servers CSV input in action.yml.
  • Docs — new section "12. PubSub Publisher" in docs/servers.md, new row in the endpoint table of docs/ci-integration.md, new row in README.md "What's Inside".

Changed

  • Pinned UA-.NETStandard NuGet version to 1.5.378.134 (previously 1.5.*). The wildcard would auto-upgrade on every Docker build, which defeats the purpose of a stable interop counterpart: any upstream change to protocol semantics would silently break every client test run until someone noticed. Pinning makes NuGet upgrades an explicit decision.
    • Why 1.5.378.134 specifically: it is the latest stable (released 2026-03-26) that predates the "Secure channel enhancements 2025 11" rework in UA-.NETStandard master (commit d188383, merged 2026-04-16). That rework turns on strict OPC UA 1.05.4 ECC behaviour — first sequence number for ECC policies MUST be 0, with wrap at UInt32.MaxValue — and adds _AesGcm / _ChaChaPoly policy variants. A client speaking 1.05.3 ECC against a strict server would fail at the first message.
    • When to bump: once a client in the ecosystem (e.g. php-opcua/opcua-client) ships the 1.05.4 ECC fix, coordinate a bump here and in the client's integration tests in the same release train.

v1.1.0

Choose a tag to compare

@GianfriAurGianfriAur released this 10 Apr 09:53
1a5af0f

ECC Security Policies

  • 2 new server instances for Elliptic Curve Cryptography (ECC) security policies (ports 4848-4849).
  • Server 9 — ECC NIST (opcua-ecc-nist, port 4848): ECC_nistP256 and ECC_nistP384 policies with NIST P-256/P-384 curves.
  • Server 10 — ECC Brainpool (opcua-ecc-brainpool, port 4849): ECC_brainpoolP256r1 and ECC_brainpoolP384r1 policies (European BSI standard).
  • ECC certificates auto-generated by UA-.NETStandard SDK via ApplicationCertificates collection with CertificateType mapping.
  • Updated GitHub Actions composite action (action.yml) with ecc-nist, ecc-brainpool server options.
  • Updated CI compose overrides (docker-compose.ci.yml) for the 2 new services.
  • Upgraded to .NET 10.0 runtime and SDK.

v1.0.0

Choose a tag to compare

@GianfriAurGianfriAur released this 02 Apr 13:37
21c71e6

UA-.NETStandard Test Suite v1.0.0

This is the evolution of php-opcua/opcua-test-suite (v1.1.5), completely rewritten from Node.js/node-opcua to .NET 8.0/UA-.NETStandard.

Why the switch?

UA-.NETStandard is the reference implementation maintained directly by the OPC Foundation — the same organization that writes the OPC UA specification. This means protocol behavior, binary encoding, security handshakes, and session management
are as close to the spec as it gets. If your client works against this server, it will work against real industrial equipment.

What's included

  • 8 pre-configured OPC UA servers via Docker Compose (ports 4840-4847) covering all security policies, authentication methods, and communication modes
  • ~300 address space nodes including 21 scalar types, 20 array types, 3 multi-dimensional matrices, 3 analog items with range metadata
  • 12 callable methods — arithmetic, string operations, arrays, async, error handling, multi-output, event generation
  • 13 dynamic variables — counters, sine/sawtooth/triangle waves, random values, status cycling
  • 3 event types with periodic emission + 3 alarm types (ExclusiveLimit, NonExclusiveLimit, OffNormal)
  • 4 historical variables with HistoryRead support (1000ms recording, up to 10,000 samples)
  • 2 extension objects with binary-encoded ExtensionObject values (TestPointXYZ, TestRangeStruct)
  • Structured objects with nesting up to 10 levels deep
  • Role-based access control — admin, operator, viewer roles with enforced write restrictions
  • Real certificate validation on the strict server (port 4842) — untrusted certs are rejected
  • 50 access control variables covering every combination of data type and access level
  • 4 OPC UA Views for filtered browsing
  • Auto-generated certificates (CA, server, client, self-signed, expired) via OpenSSL
  • GitHub Actions composite action for one-line CI integration
  • Comprehensive documentation with 19 reference docs + machine-readable AI reference

Migration from opcua-test-suite

This is a drop-in replacement. Same ports, same endpoints, same address space structure, same user accounts, same certificate layout. If your tests worked with opcua-test-suite, they work with this — just swap the Docker image.

The only notable differences:

  • Namespace index 1 is now urn:opcua:testserver:nodes (was urn:opcua:test-server:<ServerName>)
  • Extension object TypeIds are in namespace 3 (urn:opcua:test-server:custom-types)
  • Historical data records at 1000ms (was 1000ms in node-opcua too)
  • Server auto-generates its own application certificate via CheckApplicationInstanceCertificates()