Releases: php-opcua/uanetstandard-test-suite
Release list
v1.5.2
v1.5.2 - 2026-06-10
Fixed ? Custom DataType nodes (ExtensionObjectsBuilder)
DataTypeDefinitionattribute now exposed onTestPointXYZ(ns=3;i=3000) andTestRangeStruct(ns=3;i=3001) ? eachDataTypeStatecarries aStructureDefinition(X/Y/ZandLow/High/Value, allDoublescalars,DefaultEncodingIdpointing at the respective Default Binary node). Previously reading attribute 23 returnedBad_AttributeIdInvalid, so OPC UA 1.04+ clients could not discover the structure layout. Used by the strengtheneddiscoverDataTypes()integration tests inphp-opcua/opcua-client.- Encoding nodes linked via
HasEncoding(i=38) instead ofHasComponent?AddChildproduced a non-conformantHasComponentreference, so spec-compliant clients browsing forHasEncodingcould not find theDefault Binarynodes (ns=3;i=3010/ns=3;i=3011).
v1.5.1
v1.5.1 ? 2026-06-04
Fixed - Container readiness / healthcheck
--healthnow gates on a real readiness marker instead of unconditionally returning 0.TestServerApp.OnServerStartedwrites/tmp/opcua-readyonly once the server reaches the Running state and its endpoints accept requests;dotnet TestServer.dll --healthreturns exit 1 until that file exists. Previously the healthcheck returned 0 immediately, sodocker compose up --waitreported the container healthy during the server boot window ? the first client connects could race initialization and receive a top-level ServiceFaultBadServerHalted(0x800E0000). This affected fast-connecting integration suites such asphp-opcua/opcua-client-ext-reverse-connect, whose first two tests connected within ~1s of the (premature) healthy signal.- Stale marker cleared on boot ?
Program.csdeletes any leftover/tmp/opcua-readybefore starting, so a restarted container (restart: unless-stopped) is never reported healthy prematurely.
v1.5.0
v1.5.0 — 2026-05-27
Added — HTTPS Binary endpoint (Part 6 §7.4.4)
opcua-https-binarydocker-compose service — exposes bothopc.tcp://0.0.0.0:4862/UA/TestServer(internal) andopc.https://0.0.0.0:4852/UA/TestServer(host-mapped) on the same TestServer process. Used by the integration suite ofphp-opcua/opcua-client-ext-transport-https.OPCFoundation.NetStandard.Opc.Ua.Bindings.Httpsv1.5.378.134 added toTestServer.csproj— provides theHttpsTransportListenerUA-.NETStandard wires foropc.https://endpoints.EnableHttps/HttpsPortinServerConfig.cs(defaultfalse/4852), env-driven viaOPCUA_ENABLE_HTTPSandOPCUA_HTTPS_PORT. When enabled,BuildBaseAddresses(config)appends theopc.https://0.0.0.0:{HttpsPort}{ResourcePath}URI to theBaseAddressescollection.ServerConfiguration.HttpsMutualTls = false— plain TLS (no client cert) is accepted onCreateSession. 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=trueon theopcua-https-binaryservice. UA-.NETStandard'sHttpsServiceHostfilters the Anonymous user token policy out of the HTTPS endpoint description wheneverHttpsMutualTls = false, so the endpoint must advertise at least one non-anonymous policy. The HTTPS integration test connects with seededadmin/admin123credentials.- Pre-generated RSA 2048 HTTPS server certificate under
certs/https-server/(CNHttpsBinaryServer, SANlocalhost+127.0.0.1+host.docker.internal+0.0.0.0, EKUserverAuth, clientAuth). UA-.NETStandard's auto-generated application certificate defaults to 1024-bit RSA which modern TLS 1.2/1.3 rejects —scripts/generate-certs.shnow produces the stronger cert andProgram.cs::InstallPregeneratedHttpsCertificate(config)copies it into/tmp/pki/own/with the expected<CN> [<thumbprint>].der/.pfxfilename layout, computed dynamically viaX509Certificate2.Thumbprint.
v1.4.0
v1.4.0 — 2026-05-26
Added — Reverse Connect (Part 6 §7.1.2.3) test methods
TestServerAppbase class changed fromStandardServertoReverseConnectServerso the server-sideReverseConnectManager(UA-.NETStandardOpc.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.ReverseConnectMethodsBuilderundersrc/TestServer/AddressSpace/— opt-in via the newEnableReverseConnectconfig flag (defaulttrue). Adds aTestServer/ReverseConnectfolder with two Method nodes:ns=2;s=TestServer/ReverseConnect/StartReverseConnect(host: String, port: UInt16) → status: StatusCode— callsAddReverseConnection(new Uri("opc.tcp://{host}:{port}")); idempotent against double-add (treated asGood).ns=2;s=TestServer/ReverseConnect/StopReverseConnect(host: String, port: UInt16) → status: StatusCode— callsRemoveReverseConnection(...); returnsBadNotFoundif the URL was not registered,Goodotherwise.
- TestNodeManager signature extended with a fifth ctor argument
TestServerApp testServerso the Method handlers can reach the server-side reverse-connect API through the cast-free path. Empty-host / zero-port inputs both yieldBadInvalidArgumentwithout touching the underlying manager. - Env-driven toggle —
OPCUA_ENABLE_REVERSE_CONNECT(defaulttrue). When disabled theTestServer/ReverseConnectfolder 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, callsStartReverseConnect("127.0.0.1", <port>), and the server dials out and emits a ReverseHello (RHE) toward the listener.
v1.3.0
v1.3.0 — 2026-05-26
Added — File Transfer (Part 5) fixtures
FileTransferBuilderundersrc/TestServer/AddressSpace/— mirrors the existing builder pattern, self-contained, opt-in via the newEnableFileTransferconfig flag (defaulttrue). Adds aTestServer/Filesfolder with sixFileTypenodes plus oneFileDirectoryType:ns=1;s=TestServer/Files/ReadOnlyFile— 1024 B, deterministic seed (MD5("readonly-seed") × 64),Writable=false, MimeTypeapplication/octet-streamns=1;s=TestServer/Files/EmptyFile— 0 B,Writable=false, MimeTypetext/plainns=1;s=TestServer/Files/LargeFile— 256 KB, bytes0..255repeated 1024 times,Writable=false(forces chunkedReadagainst any sane negotiated max-message-size), MimeTypeapplication/octet-streamns=1;s=TestServer/Files/WritableFile— 0 B initial,Writable=true, the round-trip target forOpen(Write)→Write→Close→ re-Open(Read)test patternsns=1;s=TestServer/Files/AppendableFile— 13 B initial ("seed-content\n"),Writable=true, the target forOpen(Write | Append)semantics — the initial cursor sits at end-of-filens=1;s=TestServer/Files/ProtectedWritableFile— 0 B initial,Writable=trueadvertised but per-sessionOpen(Write)checks the identity viaUserManager: only theadminrole obtains a write handle;anonymous,operator, andviewerreceiveBad_UserAccessDenied.Open(Read)is allowed for every sessionns=1;s=TestServer/Files/RootDir— aFileDirectoryTypewith all four management methods wired (CreateDirectory,CreateFile,DeleteFileSystemObject,MoveOrCopy). Children are tracked in-process, addressable via the standard FileType/FileDirectoryType surface;MoveOrCopysupports bothcreateCopy=true(clone) andcreateCopy=false(move)
InMemoryFileBackend— per-fileMemoryStream-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 ofRootDir). Thread-safe via a single lock (UA-.NETStandard dispatchesOnCallfrom its session worker pool, so concurrent handle access is real). Snapshot helper exposed forMoveOrCopy(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 propertiesSize/Writable/UserWritable/OpenCount/MimeTypepopulated;Sizeupdated on every successfulWrite,OpenCounton everyOpen/Close. - Edge-case enforcement —
Open(0)→Bad_InvalidArgument,Open(Write)on a read-only file →Bad_NotWritable,Open(EraseExisting)withoutWrite→Bad_InvalidArgument,Read/Writeon a handle missing the required mode bit →Bad_InvalidState, unknownfileHandle→Bad_InvalidArgument,Readpast EOF → short-read (no error),Open(Write)onProtectedWritableFilewithout admin role →Bad_UserAccessDenied,CreateDirectory/CreateFilewith empty name →Bad_InvalidArgument,DeleteFileSystemObject/MoveOrCopyagainst an unknown NodeId →Bad_NodeIdUnknown. - TestNodeManager helpers —
AddNode(context, node)already exposed in earlier versions; newDeleteDynamicNode(nodeId)wrapper around the framework's internalDeleteNodeto support the directory delete/move-out paths. - Env-driven toggle —
OPCUA_ENABLE_FILE_TRANSFER(defaulttrue). Disabling skips the entireTestServer/Filesfolder construction. On by default on every classic server. - Docs — new page
docs/runtime-features/file-transfer.mdcovering NodeIds, initial content, Open mode matrix, round-trip / chunked-read test patterns, reset semantics, FileDirectoryType usage, and the per-user check onProtectedWritableFile. Cascading updates indocs/index.md,docs/address-space/overview.md(now 10/11 top-level folders, newFilesrow in the tree),docs/reference/environment-variables.md,docs/server-instances/overview.md.
v1.2.0
v1.2.0 — 2026-04-22
Added — Security Key Service (service 11, port 4851)
opcua-sksservice — new classic OPC UA server instance that boots the sharedTestServerimage withOPCUA_ENABLE_SKS=true. Exposes the OPC UA Part 14 §8.4.2GetSecurityKeysmethod underns=1;s=TestServer/SecurityKeyService, letting PubSub subscriber-side clients (e.g.php-opcua/opcua-client-ext-pubsub'sSksGroupKeyProvider) exercise the real RPC path against a live server instead of onlyMockClient.SecurityKeyServiceBuilderundersrc/TestServer/AddressSpace/— mirrors the existing builder pattern, self-contained, opt-in viaEnableSksconfig flag so the other 10 server instances are unaffected.- Env-driven config —
OPCUA_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 dedicatedopcua-sksservice. - Action update —
sksis a new option for theserversCSV input inaction.yml. - Docs — new section "11. Security Key Service" in
docs/servers.md, new row in the endpoint table ofdocs/ci-integration.md, new row inREADME.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-pubsubservice — new UA-.NETStandard UDP+UADP publisher built fromsrc/TestPublisher/(separate DockerfileDockerfile.publisher, separate.csprojagainst theOPCFoundation.NetStandard.Opc.Ua.PubSubNuGet package). Broadcasts a deterministicDataSet(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-relaysidecar pair. Publisher sends unicast UADP to the relay on a shared compose bridge (pubsub-net); the relay forwards each datagram tohost.docker.internal:14850. Subscribers on the physical host listen on127.0.0.1:14850(or0.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 theopcua-sksservice (service 11) — full end-to-end secured publisher + SKS is planned follow-up work. - Action update —
pubsubis a new option for theserversCSV input inaction.yml. - Docs — new section "12. PubSub Publisher" in
docs/servers.md, new row in the endpoint table ofdocs/ci-integration.md, new row inREADME.md"What's Inside".
Changed
- Pinned UA-.NETStandard NuGet version to
1.5.378.134(previously1.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 atUInt32.MaxValue— and adds_AesGcm/_ChaChaPolypolicy 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.
- 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
v1.1.0
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
ApplicationCertificatescollection withCertificateTypemapping. - Updated GitHub Actions composite action (
action.yml) withecc-nist,ecc-brainpoolserver 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
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(wasurn: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()