/* ======================================================================== * Copyright (c) 2005-2025 The OPC Foundation, Inc. All rights reserved. * * OPC Foundation MIT License 1.00 * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * The complete license agreement can be found here: * http://opcfoundation.org/License/MIT/1.00/ * ======================================================================*/ using System; using System.Runtime.Serialization; using Opc.Ua.Security.Certificates; namespace Opc.Ua.Client.TestFramework { /// /// Namespaces /// public static class Namespaces { /// /// The URI for the OpcUaClient namespace (.NET code namespace is 'Opc.Ua.Client'). /// public const string OpcUaClient = "http://opcfoundation.org/UA/Client/Types.xsd"; } /// /// A subclass of a session for testing purposes, e.g. to override some implementations. /// public class TestableSession : Session { /// public TestableSession( ITransportChannel channel, ApplicationConfiguration configuration, ConfiguredEndpoint endpoint, Certificate clientCertificate, ArrayOf availableEndpoints = default, ArrayOf discoveryProfileUris = default, ISubscriptionEngineFactory? engineFactory = null) : base( channel, configuration, endpoint, clientCertificate, null, availableEndpoints, discoveryProfileUris, engineFactory) { } /// public TestableSession( ITransportChannel channel, Session template, bool copyEventHandlers) : base( channel, template, copyEventHandlers) { } /// /// The timespan offset to be used to modify the request header timestamp. /// [DataMember] public TimeSpan TimestampOffset { get; set; } = new TimeSpan(0); /// protected override void UpdateRequestHeader( IServiceRequest request, bool useDefaults, string serviceName) { base.UpdateRequestHeader(request, useDefaults, serviceName); request.RequestHeader.Timestamp += TimestampOffset; } /// public override Session CloneSession(ITransportChannel channel, bool copyEventHandlers) { return new TestableSession(channel, this, copyEventHandlers) { TimestampOffset = TimestampOffset }; } /// protected override Subscription CreateSubscription(SubscriptionOptions? options) { return new TestableSubscription(MessageContext.Telemetry, options); } /// public override void Snapshot(out SessionState state) { base.Snapshot(out state); state = new TestableSessionState(state) { TimestampOffset = TimestampOffset }; } /// public override void Restore(SessionState state) { if (state is TestableSessionState s) { TimestampOffset = s.TimestampOffset; } base.Restore(state); } } /// /// Testable session state /// [DataContract(Namespace = Namespaces.OpcUaClient)] [KnownType(typeof(MonitoredItemState))] [KnownType(typeof(SubscriptionState))] public record class TestableSessionState : SessionState { /// /// Default constructor /// public TestableSessionState() { } /// /// Create a new instance of the class. /// /// public TestableSessionState(SessionState state) : base(state) { } /// /// The timespan offset to be used to modify the request header timestamp. /// [DataMember] public TimeSpan TimestampOffset { get; set; } = new TimeSpan(0); } /// /// A subclass of the subscription for testing purposes. /// public class TestableSubscription : Subscription { /// /// Constructs a new instance of the class. /// public TestableSubscription(ITelemetryContext telemetry, SubscriptionOptions? options = null) : base(telemetry, options) { } /// /// Constructs a new instance of the class. /// public TestableSubscription(Subscription template, bool copyEventHandlers = false) : base(template, copyEventHandlers) { } /// public override Subscription CloneSubscription(bool copyEventHandlers) { return new TestableSubscription(this, copyEventHandlers); } /// protected override MonitoredItem CreateMonitoredItem(MonitoredItemOptions? options) { return new TestableMonitoredItem(Telemetry!, options); } } /// /// A subclass of a monitored item for testing purposes. /// public class TestableMonitoredItem : MonitoredItem { /// /// Constructs a new instance of the class. /// public TestableMonitoredItem(ITelemetryContext telemetry, MonitoredItemOptions? options = null) : base(telemetry, options) { } /// /// Constructs a new instance of the class. /// public TestableMonitoredItem(MonitoredItem template) : this(template, false, false) { } /// /// Constructs a new instance of the class. /// public TestableMonitoredItem( MonitoredItem template, bool copyEventHandlers, bool copyClientHandle) : base(template, copyEventHandlers, copyClientHandle) { } /// public override MonitoredItem CloneMonitoredItem( bool copyEventHandlers, bool copyClientHandle) { return new TestableMonitoredItem(this, copyEventHandlers, copyClientHandle); } } }