PHP Classes

File: tests/Unit/Protocol/ServiceDiagnosticTest.php

Recommend this page to a friend!
  Packages of Gianfrancesco Aurecchia   OPC UA Client   tests/Unit/Protocol/ServiceDiagnosticTest.php   Download  
File: tests/Unit/Protocol/ServiceDiagnosticTest.php
Role: Example script
Content type: text/plain
Description: Example script
Class: OPC UA Client
Control devices that support the OPC UA protocol
Author: By
Last change:
Date: 19 days ago
Size: 13,907 bytes
 

Contents

Class file image Download
<?php declare(strict_types=1); use PhpOpcua\Client\Encoding\BinaryDecoder; use PhpOpcua\Client\Encoding\BinaryEncoder; use PhpOpcua\Client\Module\Browse\BrowseService; use PhpOpcua\Client\Module\ReadWrite\CallService; use PhpOpcua\Client\Module\ReadWrite\ReadService; use PhpOpcua\Client\Module\Subscription\SubscriptionService; use PhpOpcua\Client\Protocol\MessageHeader; use PhpOpcua\Client\Protocol\SessionService; use PhpOpcua\Client\Security\SecureChannel; use PhpOpcua\Client\Security\SecurityMode; use PhpOpcua\Client\Security\SecurityPolicy; use PhpOpcua\Client\Types\BrowseDirection; use PhpOpcua\Client\Types\BuiltinType; use PhpOpcua\Client\Types\NodeId; use PhpOpcua\Client\Types\Variant; function writeDiagResponseHeader(BinaryEncoder $encoder, int $statusCode = 0): void { $encoder->writeInt64(0); $encoder->writeUInt32(1); $encoder->writeUInt32($statusCode); $encoder->writeByte(0); $encoder->writeInt32(0); $encoder->writeNodeId(NodeId::numeric(0, 0)); $encoder->writeByte(0); } function writeDiagMessagePrefix(BinaryEncoder $encoder): void { $encoder->writeUInt32(1); $encoder->writeUInt32(1); $encoder->writeUInt32(1); } /** * Writes a diagnostic info with all fields (mask 0x1F) into the encoder. */ function writeSampleDiagnosticInfo(BinaryEncoder $encoder): void { $encoder->writeByte(0x1F); // all fields except inner $encoder->writeInt32(1); // symbolicId $encoder->writeInt32(2); // namespaceUri $encoder->writeInt32(3); // locale $encoder->writeString('details'); // additionalInfo $encoder->writeUInt32(0x80010000); // innerStatusCode } describe('ReadService with diagnostic info', function () { it('decodes ReadResponse with diagnostic infos', function () { $session = new SessionService(1, 1); $service = new ReadService($session); $encoder = new BinaryEncoder(); writeDiagMessagePrefix($encoder); $encoder->writeNodeId(NodeId::numeric(0, 634)); writeDiagResponseHeader($encoder); // Results: 1 DataValue $encoder->writeInt32(1); $encoder->writeByte(0x01); // value only $encoder->writeByte(BuiltinType::Int32->value); $encoder->writeInt32(42); // DiagnosticInfos: 1 $encoder->writeInt32(1); writeSampleDiagnosticInfo($encoder); $decoder = new BinaryDecoder($encoder->getBuffer()); $results = $service->decodeReadMultiResponse($decoder); expect($results)->toHaveCount(1); expect($results[0]->getValue())->toBe(42); }); it('decodes single ReadResponse returning default DataValue when empty', function () { $session = new SessionService(1, 1); $service = new ReadService($session); $encoder = new BinaryEncoder(); writeDiagMessagePrefix($encoder); $encoder->writeNodeId(NodeId::numeric(0, 634)); writeDiagResponseHeader($encoder); // Results: 0 $encoder->writeInt32(0); // DiagnosticInfos: 0 $encoder->writeInt32(0); $decoder = new BinaryDecoder($encoder->getBuffer()); $result = $service->decodeReadResponse($decoder); expect($result->getValue())->toBeNull(); }); }); describe('CallService with diagnostic info', function () { it('decodes CallResponse with inputArgumentResults and diagnosticInfos', function () { $session = new SessionService(1, 1); $service = new CallService($session); $encoder = new BinaryEncoder(); writeDiagMessagePrefix($encoder); $encoder->writeNodeId(NodeId::numeric(0, 715)); writeDiagResponseHeader($encoder); // Results: 1 CallMethodResult $encoder->writeInt32(1); $encoder->writeUInt32(0); // StatusCode // InputArgumentResults: 2 $encoder->writeInt32(2); $encoder->writeUInt32(0); // Good $encoder->writeUInt32(0x80010000); // Bad // InputArgumentDiagnosticInfos: 1 $encoder->writeInt32(1); writeSampleDiagnosticInfo($encoder); // OutputArguments: 1 $encoder->writeInt32(1); $encoder->writeByte(BuiltinType::String->value); $encoder->writeString('result'); // Top-level DiagnosticInfos: 1 $encoder->writeInt32(1); writeSampleDiagnosticInfo($encoder); $decoder = new BinaryDecoder($encoder->getBuffer()); $result = $service->decodeCallResponse($decoder); expect($result->statusCode)->toBe(0); expect($result->inputArgumentResults)->toBe([0, 0x80010000]); expect($result->outputArguments)->toHaveCount(1); expect($result->outputArguments[0]->getValue())->toBe('result'); }); it('decodes CallResponse with no results', function () { $session = new SessionService(1, 1); $service = new CallService($session); $encoder = new BinaryEncoder(); writeDiagMessagePrefix($encoder); $encoder->writeNodeId(NodeId::numeric(0, 715)); writeDiagResponseHeader($encoder); // 0 results $encoder->writeInt32(0); // DiagnosticInfos: 0 $encoder->writeInt32(0); $decoder = new BinaryDecoder($encoder->getBuffer()); $result = $service->decodeCallResponse($decoder); expect($result->statusCode)->toBe(0); expect($result->inputArgumentResults)->toBe([]); expect($result->outputArguments)->toBe([]); }); }); describe('SubscriptionService with diagnostic info', function () { it('decodes DeleteSubscriptionsResponse with diagnostic infos', function () { $session = new SessionService(1, 1); $service = new SubscriptionService($session); $encoder = new BinaryEncoder(); writeDiagMessagePrefix($encoder); $encoder->writeNodeId(NodeId::numeric(0, 850)); writeDiagResponseHeader($encoder); // Results: 2 status codes $encoder->writeInt32(2); $encoder->writeUInt32(0); $encoder->writeUInt32(0x80700000); // DiagnosticInfos: 1 with inner diagnostic $encoder->writeInt32(1); // Outer: has symbolicId + innerDiagnosticInfo $encoder->writeByte(0x21); $encoder->writeInt32(42); // symbolicId // Inner: has additionalInfo only $encoder->writeByte(0x08); $encoder->writeString('inner details'); $decoder = new BinaryDecoder($encoder->getBuffer()); $result = $service->decodeDeleteSubscriptionsResponse($decoder); expect($result)->toHaveCount(2); expect($result[0])->toBe(0); expect($result[1])->toBe(0x80700000); }); it('decodes SetPublishingModeResponse with diagnostic infos', function () { $session = new SessionService(1, 1); $service = new SubscriptionService($session); $encoder = new BinaryEncoder(); writeDiagMessagePrefix($encoder); $encoder->writeNodeId(NodeId::numeric(0, 802)); writeDiagResponseHeader($encoder); // Results: 1 $encoder->writeInt32(1); $encoder->writeUInt32(0); // DiagnosticInfos: 1 $encoder->writeInt32(1); writeSampleDiagnosticInfo($encoder); $decoder = new BinaryDecoder($encoder->getBuffer()); $result = $service->decodeSetPublishingModeResponse($decoder); expect($result)->toBe([0]); }); }); describe('BrowseService encoding and decoding', function () { it('encodes a BrowseNext request', function () { $session = new SessionService(1, 1); $service = new BrowseService($session); $bytes = $service->encodeBrowseNextRequest(1, 'continuation-point', NodeId::numeric(0, 0)); $decoder = new BinaryDecoder($bytes); $header = MessageHeader::decode($decoder); expect($header->getMessageType())->toBe('MSG'); }); it('decodes BrowseNextResponse with references', function () { $session = new SessionService(1, 1); $service = new BrowseService($session); $encoder = new BinaryEncoder(); writeDiagMessagePrefix($encoder); $encoder->writeNodeId(NodeId::numeric(0, 536)); // BrowseNextResponse writeDiagResponseHeader($encoder); // Results: 1 $encoder->writeInt32(1); $encoder->writeUInt32(0); // StatusCode $encoder->writeByteString(null); // ContinuationPoint // References: 1 $encoder->writeInt32(1); // ReferenceDescription $encoder->writeNodeId(NodeId::numeric(0, 35)); $encoder->writeBoolean(true); $encoder->writeExpandedNodeId(NodeId::numeric(1, 500)); $encoder->writeUInt16(1); $encoder->writeString('Var1'); $encoder->writeByte(0x02); $encoder->writeString('Variable 1'); $encoder->writeUInt32(2); // Variable $encoder->writeExpandedNodeId(NodeId::numeric(0, 62)); // DiagnosticInfos: 0 $encoder->writeInt32(0); $decoder = new BinaryDecoder($encoder->getBuffer()); $result = $service->decodeBrowseNextResponse($decoder); expect($result->references)->toHaveCount(1); expect($result->references[0]->getBrowseName()->getName())->toBe('Var1'); expect($result->continuationPoint)->toBeNull(); }); it('decodes BrowseResponse with diagnosticInfos', function () { $session = new SessionService(1, 1); $service = new BrowseService($session); $encoder = new BinaryEncoder(); writeDiagMessagePrefix($encoder); $encoder->writeNodeId(NodeId::numeric(0, 530)); writeDiagResponseHeader($encoder); $encoder->writeInt32(1); $encoder->writeUInt32(0); $encoder->writeByteString(null); $encoder->writeInt32(0); $encoder->writeInt32(1); $encoder->writeByte(0x01); $encoder->writeInt32(42); $decoder = new BinaryDecoder($encoder->getBuffer()); $result = $service->decodeBrowseResponseWithContinuation($decoder); expect($result->references)->toBe([]); }); it('encodes BrowseRequest with custom reference type', function () { $session = new SessionService(1, 1); $service = new BrowseService($session); $bytes = $service->encodeBrowseRequest( 1, NodeId::numeric(0, 85), NodeId::numeric(0, 0), BrowseDirection::Forward, NodeId::numeric(0, 35), false, 0xFF, ); $decoder = new BinaryDecoder($bytes); $header = MessageHeader::decode($decoder); expect($header->getMessageType())->toBe('MSG'); expect(strlen($bytes))->toBeGreaterThan(50); }); }); describe('CallService encoding', function () { it('encodes a CallRequest with input arguments', function () { $session = new SessionService(1, 1); $service = new CallService($session); $bytes = $service->encodeCallRequest( 1, NodeId::numeric(0, 2253), NodeId::numeric(0, 11492), [ new Variant(BuiltinType::String, 'arg1'), new Variant(BuiltinType::Int32, 42), ], NodeId::numeric(0, 0), ); $decoder = new BinaryDecoder($bytes); $header = MessageHeader::decode($decoder); expect($header->getMessageType())->toBe('MSG'); expect(strlen($bytes))->toBeGreaterThan(50); }); }); describe('ReadService encoding', function () { it('encodes a single ReadRequest', function () { $session = new SessionService(1, 1); $service = new ReadService($session); $bytes = $service->encodeReadRequest(1, NodeId::numeric(1, 100), NodeId::numeric(0, 0)); $decoder = new BinaryDecoder($bytes); $header = MessageHeader::decode($decoder); expect($header->getMessageType())->toBe('MSG'); }); it('encodes a single ReadRequest with custom attributeId', function () { $session = new SessionService(1, 1); $service = new ReadService($session); $bytes = $service->encodeReadRequest(1, NodeId::numeric(1, 100), NodeId::numeric(0, 0), 1); expect(strlen($bytes))->toBeGreaterThan(30); }); }); describe('SessionService additional coverage', function () { it('getSecureChannelId delegates to SecureChannel when present', function () { $sc = new SecureChannel( SecurityPolicy::None, SecurityMode::None, ); $session = new SessionService(0, 0, $sc); // SecureChannel starts with channelId=0 expect($session->getSecureChannelId())->toBe(0); }); it('getTokenId delegates to SecureChannel when present', function () { $sc = new SecureChannel( SecurityPolicy::None, SecurityMode::None, ); $session = new SessionService(0, 0, $sc); expect($session->getTokenId())->toBe(0); }); it('getNextSequenceNumber delegates to SecureChannel when present', function () { $sc = new SecureChannel( SecurityPolicy::None, SecurityMode::None, ); $session = new SessionService(0, 0, $sc); expect($session->getNextSequenceNumber())->toBe(1); expect($session->getNextSequenceNumber())->toBe(2); }); it('setUserTokenPolicyIds updates policy IDs', function () { $session = new SessionService(1, 1); $session->setUserTokenPolicyIds('user1', 'cert1', 'anon1'); // No direct getter, but this exercises lines 36-44 expect(true)->toBeTrue(); }); it('setUserTokenPolicyIds with null does not change values', function () { $session = new SessionService(1, 1); $session->setUserTokenPolicyIds(null, null, null); expect(true)->toBeTrue(); }); });