From 22e2a535510dfb4cb599cfabdda54bcf98fb6c9f Mon Sep 17 00:00:00 2001 From: Pavel Gross Date: Fri, 16 Aug 2024 12:09:17 +0300 Subject: [PATCH] [#16] Client: Unit tests Signed-off-by: Pavel Gross --- .../Tools/ClientEnvironment.cs | 1 + .../ContainerServiceBase.cs | 6 + src/FrostFS.SDK.Tests/Mocks/NetworkMocker.cs | 83 ++++- src/FrostFS.SDK.Tests/Mocks/SessionMock.cs | 49 +-- src/FrostFS.SDK.Tests/NetworkTest.cs | 303 ++++++++++++++++++ src/FrostFS.SDK.Tests/SessionTests.cs | 127 ++++++++ 6 files changed, 544 insertions(+), 25 deletions(-) create mode 100644 src/FrostFS.SDK.Tests/NetworkTest.cs create mode 100644 src/FrostFS.SDK.Tests/SessionTests.cs diff --git a/src/FrostFS.SDK.ClientV2/Tools/ClientEnvironment.cs b/src/FrostFS.SDK.ClientV2/Tools/ClientEnvironment.cs index ec06eab..6fe2f15 100644 --- a/src/FrostFS.SDK.ClientV2/Tools/ClientEnvironment.cs +++ b/src/FrostFS.SDK.ClientV2/Tools/ClientEnvironment.cs @@ -3,6 +3,7 @@ using Grpc.Net.Client; using System; using System.Security.Cryptography; using FrostFS.SDK.Cryptography; +using System.Buffers; namespace FrostFS.SDK.ClientV2; diff --git a/src/FrostFS.SDK.Tests/Mocks/ContainerServiceMocks/ContainerServiceBase.cs b/src/FrostFS.SDK.Tests/Mocks/ContainerServiceMocks/ContainerServiceBase.cs index 9de903c..7cf2690 100644 --- a/src/FrostFS.SDK.Tests/Mocks/ContainerServiceMocks/ContainerServiceBase.cs +++ b/src/FrostFS.SDK.Tests/Mocks/ContainerServiceMocks/ContainerServiceBase.cs @@ -27,6 +27,12 @@ public abstract class ServiceBase(string key) public static BasicAcl DefaultAcl { get; } = BasicAcl.PublicRW; public static PlacementPolicy DefaultPlacementPolicy { get; } = new PlacementPolicy(true, new Replica(1)); + public Metadata Metadata { get; protected set; } + public DateTime? DateTime { get; protected set; } + public CancellationToken CancellationToken { get; protected set; } + + public CancellationTokenSource CancellationTokenSource { get; protected set; } = new CancellationTokenSource(); + public static Metadata ResponseMetaData => []; protected ResponseVerificationHeader GetResponseVerificationHeader(IResponse response) diff --git a/src/FrostFS.SDK.Tests/Mocks/NetworkMocker.cs b/src/FrostFS.SDK.Tests/Mocks/NetworkMocker.cs index f078df6..ace5c9f 100644 --- a/src/FrostFS.SDK.Tests/Mocks/NetworkMocker.cs +++ b/src/FrostFS.SDK.Tests/Mocks/NetworkMocker.cs @@ -3,24 +3,40 @@ using FrostFS.Netmap; using Grpc.Core; using FrostFS.SDK.ClientV2; using Google.Protobuf; +using FrostFS.SDK.ModelsV2; namespace FrostFS.SDK.Tests; public class NetworkMocker(string key) : ServiceBase(key) { - private static readonly string[] parameterKeys = [ + internal static readonly string[] ParameterKeys = [ + "AuditFee", + "BasicIncomeRate", "ContainerFee", + "ContainerAliasFee", "EpochDuration", - "IRCandidateFee", + "InnerRingCandidateFee", "MaxECDataCount", "MaxECParityCount", "MaxObjectSize", - "WithdrawalFee", + "WithdrawFee", "HomomorphicHashingDisabled", - "MaintenanceModeAllowed" ]; + "MaintenanceModeAllowed" + ]; public Dictionary? Parameters { get; set; } + public LocalNodeInfoResponse NodeInfoResponse { get; set; } + + public LocalNodeInfoRequest LocalNodeInfoRequest { get; set; } + + public NetworkInfoRequest NetworkInfoRequest { get; set; } + + public NetmapSnapshotResponse NetmapSnapshotResponse { get; set; } + + public NetmapSnapshotRequest NetmapSnapshotRequest { get; set; } + + public Mock GetMock() { var mock = new Mock(); @@ -29,7 +45,7 @@ public class NetworkMocker(string key) : ServiceBase(key) var networkConfig = new NetworkConfig(); - foreach (var key in parameterKeys) + foreach (var key in ParameterKeys) { networkConfig.Parameters.Add(new NetworkConfig.Types.Parameter { @@ -62,7 +78,10 @@ public class NetworkMocker(string key) : ServiceBase(key) It.IsAny())) .Returns((NetworkInfoRequest r, Metadata m, DateTime? dt, CancellationToken ct) => { - Verifier.CheckRequest(r); + NetworkInfoRequest = r; + Metadata = m; + DateTime = dt; + CancellationToken = ct; return new AsyncUnaryCall( Task.FromResult(response), @@ -72,6 +91,58 @@ public class NetworkMocker(string key) : ServiceBase(key) () => { }); }); + if (NodeInfoResponse != null) + { + NodeInfoResponse.MetaHeader = ResponseMetaHeader; + NodeInfoResponse.VerifyHeader = GetResponseVerificationHeader(NodeInfoResponse); + + mock.Setup(x => x.LocalNodeInfoAsync( + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())) + .Returns((LocalNodeInfoRequest r, Metadata m, DateTime? dt, CancellationToken ct) => + { + LocalNodeInfoRequest = r; + Metadata = m; + DateTime = dt; + CancellationToken = ct; + + return new AsyncUnaryCall( + Task.FromResult(NodeInfoResponse), + Task.FromResult(ResponseMetaData), + () => new Grpc.Core.Status(StatusCode.OK, string.Empty), + () => ResponseMetaData, + () => { }); + }); + } + + if (NetmapSnapshotResponse != null) + { + NetmapSnapshotResponse.MetaHeader = ResponseMetaHeader; + NetmapSnapshotResponse.VerifyHeader = GetResponseVerificationHeader(NetmapSnapshotResponse); + + mock.Setup(x => x.NetmapSnapshotAsync( + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())) + .Returns((NetmapSnapshotRequest r, Metadata m, DateTime? dt, CancellationToken ct) => + { + NetmapSnapshotRequest = r; + Metadata = m; + DateTime = dt; + CancellationToken = ct; + + return new AsyncUnaryCall( + Task.FromResult(NetmapSnapshotResponse), + Task.FromResult(ResponseMetaData), + () => new Grpc.Core.Status(StatusCode.OK, string.Empty), + () => ResponseMetaData, + () => { }); + }); + } + return mock; } } diff --git a/src/FrostFS.SDK.Tests/Mocks/SessionMock.cs b/src/FrostFS.SDK.Tests/Mocks/SessionMock.cs index 094090d..e1800b6 100644 --- a/src/FrostFS.SDK.Tests/Mocks/SessionMock.cs +++ b/src/FrostFS.SDK.Tests/Mocks/SessionMock.cs @@ -1,8 +1,7 @@ -using Moq; using FrostFS.Session; -using Grpc.Core; -using FrostFS.SDK.ClientV2; using Google.Protobuf; +using Grpc.Core; +using Moq; namespace FrostFS.SDK.Tests; @@ -11,24 +10,33 @@ public class SessionMocker(string key) : ServiceBase(key) public byte[]? SessionId { get; set; } public byte[]? SessionKey { get; set; } - + + public CreateRequest CreateSessionRequest { get; private set; } + public Mock GetMock() { var mock = new Mock(); Random rand = new(); - SessionId = new byte[32]; - SessionKey = new byte[32]; - rand.NextBytes(SessionId); - rand.NextBytes(SessionKey); + if (SessionId == null) + { + SessionId = new byte[32]; + rand.NextBytes(SessionId); + } + + if (SessionKey == null) + { + SessionKey = new byte[32]; + rand.NextBytes(SessionKey); + } CreateResponse response = new() { Body = new CreateResponse.Types.Body { Id = ByteString.CopyFrom(SessionId), - SessionKey = ByteString.CopyFrom(SessionId) + SessionKey = ByteString.CopyFrom(SessionKey) }, MetaHeader = ResponseMetaHeader }; @@ -40,17 +48,20 @@ public class SessionMocker(string key) : ServiceBase(key) It.IsAny(), It.IsAny(), It.IsAny())) - .Returns((CreateRequest r, Metadata m, DateTime? dt, CancellationToken ct) => - { - Verifier.CheckRequest(r); + .Returns((CreateRequest r, Metadata m, DateTime? dt, CancellationToken ct) => + { + CreateSessionRequest = r; + Metadata = m; + DateTime = dt; + CancellationToken = ct; - return new AsyncUnaryCall( - Task.FromResult(response), - Task.FromResult(ResponseMetaData), - () => new Grpc.Core.Status(StatusCode.OK, string.Empty), - () => ResponseMetaData, - () => { }); - }); + return new AsyncUnaryCall( + Task.FromResult(response), + Task.FromResult(ResponseMetaData), + () => new Grpc.Core.Status(StatusCode.OK, string.Empty), + () => ResponseMetaData, + () => { }); + }); return mock; } diff --git a/src/FrostFS.SDK.Tests/NetworkTest.cs b/src/FrostFS.SDK.Tests/NetworkTest.cs new file mode 100644 index 0000000..35959d3 --- /dev/null +++ b/src/FrostFS.SDK.Tests/NetworkTest.cs @@ -0,0 +1,303 @@ +using FrostFS.Netmap; +using FrostFS.SDK.ClientV2; +using FrostFS.SDK.ClientV2.Interfaces; +using FrostFS.SDK.ClientV2.Parameters; +using FrostFS.SDK.Cryptography; +using FrostFS.SDK.ModelsV2; +using FrostFS.SDK.ModelsV2.Enums; +using Google.Protobuf; +using Microsoft.Extensions.Options; +using System.Security.Cryptography; +using System.Threading; + +namespace FrostFS.SDK.Tests; + +public abstract class NetworkTestsBase +{ + protected readonly string key = "KwHDAJ66o8FoLBjVbjP2sWBmgBMGjt7Vv4boA7xQrBoAYBE397Aq"; + + protected IOptions Settings { get; set; } + + protected ModelsV2.Version Version { get; set; } = new ModelsV2.Version(2, 13); + + protected ECDsa ECDsaKey { get; set; } + protected OwnerId OwnerId { get; set; } + protected NetworkMocker Mocker { get; set; } + + protected NetworkTestsBase() + { + Settings = Options.Create(new SingleOwnerClientSettings + { + Key = key, + Host = "http://localhost:8080" + }); + + ECDsaKey = key.LoadWif(); + OwnerId = OwnerId.FromKey(ECDsaKey); + + Mocker = new NetworkMocker(this.key); + } + + protected IFrostFSClient GetClient() + { + return ClientV2.Client.GetTestInstance( + Settings, + null, + Mocker.GetMock().Object, + new SessionMocker(this.key).GetMock().Object, + new ContainerMocker(this.key).GetMock().Object, + new ObjectMocker(this.key).GetMock().Object); + } +} + +public class NetworkTest : NetworkTestsBase +{ + [Theory] + [InlineData(false)] + [InlineData(true)] + public async void NetworkSettingsTest(bool useContext) + { + Mocker.Parameters = new Dictionary + { + { "AuditFee", [1] }, + { "BasicIncomeRate", [2] }, + { "ContainerFee", [3] }, + { "ContainerAliasFee", [4] }, + { "EpochDuration", [5] }, + { "InnerRingCandidateFee", [6] }, + { "MaxECDataCount", [7] }, + { "MaxECParityCount", [8] }, + { "MaxObjectSize", [9] }, + { "WithdrawFee", [10] }, + { "HomomorphicHashingDisabled", [1] }, + { "MaintenanceModeAllowed", [1] }, + }; + + var param = new PrmNetworkSettings(); + + if (useContext) + { + param.Context = new Context + { + CancellationToken = Mocker.CancellationTokenSource.Token, + Timeout = TimeSpan.FromSeconds(20), + OwnerId = OwnerId, + Key = ECDsaKey, + Version = Version + }; + } + + var validTimeoutFrom = DateTime.UtcNow.AddSeconds(20); + + var result = await GetClient().GetNetworkSettingsAsync(param); + + var validTimeoutTo = DateTime.UtcNow.AddSeconds(20); + + Assert.NotNull(result); + + Assert.Equal(Mocker.Parameters["AuditFee"], [(byte)result.AuditFee]); + Assert.Equal(Mocker.Parameters["BasicIncomeRate"], [(byte)result.BasicIncomeRate]); + Assert.Equal(Mocker.Parameters["ContainerFee"], [(byte)result.ContainerFee]); + Assert.Equal(Mocker.Parameters["ContainerAliasFee"], [(byte)result.ContainerAliasFee]); + Assert.Equal(Mocker.Parameters["EpochDuration"], [(byte)result.EpochDuration]); + Assert.Equal(Mocker.Parameters["InnerRingCandidateFee"], [(byte)result.InnerRingCandidateFee]); + Assert.Equal(Mocker.Parameters["MaxECDataCount"], [(byte)result.MaxECDataCount]); + Assert.Equal(Mocker.Parameters["MaxECParityCount"], [(byte)result.MaxECParityCount]); + Assert.Equal(Mocker.Parameters["MaxObjectSize"], [(byte)result.MaxObjectSize]); + Assert.Equal(Mocker.Parameters["WithdrawFee"], [(byte)result.WithdrawFee]); + + Assert.True(result.HomomorphicHashingDisabled); + Assert.True(result.MaintenanceModeAllowed); + + if (useContext) + { + Assert.Equal(Mocker.CancellationTokenSource.Token, Mocker.CancellationToken); + Assert.NotNull(Mocker.DateTime); + + Assert.True(Mocker.DateTime.Value >= validTimeoutFrom); + Assert.True(Mocker.DateTime.Value <= validTimeoutTo); + } + else + { + Assert.Empty(Mocker.NetworkInfoRequest.MetaHeader.XHeaders); + Assert.Null(Mocker.DateTime); + } + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public async void NetmapSnapshotTest(bool useContext) + { + var body = new NetmapSnapshotResponse.Types.Body + { + Netmap = new Netmap.Netmap { Epoch = 99 } + }; + + var nodeInfo1 = new NodeInfo + { + State = NodeInfo.Types.State.Online, + PublicKey = ByteString.CopyFrom([1, 2, 3]) + }; + + nodeInfo1.Addresses.Add("address1"); + nodeInfo1.Addresses.Add("address2"); + nodeInfo1.Attributes.Add(new NodeInfo.Types.Attribute { Key = "key1", Value = "value1"}); + nodeInfo1.Attributes.Add(new NodeInfo.Types.Attribute { Key = "key2", Value = "value2" }); + + var nodeInfo2 = new NodeInfo + { + State = NodeInfo.Types.State.Offline, + PublicKey = ByteString.CopyFrom([3,4,5]) + }; + + nodeInfo2.Addresses.Add("address3"); + nodeInfo2.Attributes.Add(new NodeInfo.Types.Attribute { Key = "key3", Value = "value3" }); + + body.Netmap.Nodes.Add(nodeInfo1); + body.Netmap.Nodes.Add(nodeInfo2); + + Mocker.NetmapSnapshotResponse = new NetmapSnapshotResponse { Body = body }; + + var param = new PrmNetmapSnapshot(); + + if (useContext) + { + param.XHeaders.Add("headerKey1", "headerValue1"); + param.Context = new Context + { + CancellationToken = Mocker.CancellationTokenSource.Token, + Timeout = TimeSpan.FromSeconds(20), + OwnerId = OwnerId, + Key = ECDsaKey, + Version = Version + }; + } + + var validTimeoutFrom = DateTime.UtcNow.AddSeconds(20); + + var result = await GetClient().GetNetmapSnapshotAsync(param); + + var validTimeoutTo = DateTime.UtcNow.AddSeconds(20); + + Assert.NotNull(result); + + Assert.Equal(99u, result.Epoch); + Assert.Equal(2, result.NodeInfoCollection.Count); + + var node1 = result.NodeInfoCollection[0]; + Assert.Equal(NodeState.Online, node1.State); + Assert.Equal(2, node1.Addresses.Count); + Assert.Equal("address1", node1.Addresses.ElementAt(0)); + Assert.Equal("address2", node1.Addresses.ElementAt(1)); + + Assert.Equal(2, node1.Attributes.Count); + + Assert.Equal("key1", node1.Attributes.ElementAt(0).Key); + Assert.Equal("value1", node1.Attributes.ElementAt(0).Value); + Assert.Equal("key2", node1.Attributes.ElementAt(1).Key); + Assert.Equal("value2", node1.Attributes.ElementAt(1).Value); + + var node2 = result.NodeInfoCollection[1]; + Assert.Equal(NodeState.Offline, node2.State); + Assert.Single(node2.Addresses); + Assert.Equal("address3", node2.Addresses.ElementAt(0)); + + Assert.Single(node2.Attributes); + + Assert.Equal("key3", node2.Attributes.ElementAt(0).Key); + Assert.Equal("value3", node2.Attributes.ElementAt(0).Value); + + if (useContext) + { + Assert.Single(Mocker.NetmapSnapshotRequest.MetaHeader.XHeaders); + Assert.Equal(param.XHeaders.Keys[0], Mocker.NetmapSnapshotRequest.MetaHeader.XHeaders.First().Key); + Assert.Equal(param.XHeaders[param.XHeaders.Keys[0]], Mocker.NetmapSnapshotRequest.MetaHeader.XHeaders.First().Value); + + Assert.Equal(Mocker.CancellationTokenSource.Token, Mocker.CancellationToken); + Assert.NotNull(Mocker.DateTime); + + Assert.True(Mocker.DateTime.Value >= validTimeoutFrom); + Assert.True(Mocker.DateTime.Value <= validTimeoutTo); + } + else + { + Assert.Empty(Mocker.NetmapSnapshotRequest.MetaHeader.XHeaders); + Assert.Null(Mocker.DateTime); + } + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public async void NodeInfoTest(bool useContext) + { + var body = new LocalNodeInfoResponse.Types.Body + { + NodeInfo = new NodeInfo() + { + State = NodeInfo.Types.State.Online, + PublicKey = ByteString.CopyFrom([1, 2, 3]) + }, + Version = new Refs.Version { Major = 2, Minor = 12 } + }; + + body.NodeInfo.Addresses.Add("address1"); + body.NodeInfo.Addresses.Add("address2"); + body.NodeInfo.Attributes.Add(new NodeInfo.Types.Attribute { Key = "key1", Value = "value1"}); + body.NodeInfo.Attributes.Add(new NodeInfo.Types.Attribute { Key = "key2", Value = "value2" }); + + Mocker.NodeInfoResponse = new LocalNodeInfoResponse { Body = body }; + + var param = new PrmNodeInfo(); + + if (useContext) + { + param.XHeaders.Add("headerKey1", "headerValue1"); + param.Context = new Context + { + CancellationToken = Mocker.CancellationTokenSource.Token, + Timeout = TimeSpan.FromSeconds(20), + OwnerId = OwnerId, + Key = ECDsaKey, + Version = Version + }; + } + + var validTimeoutFrom = DateTime.UtcNow.AddSeconds(20); + + var result = await GetClient().GetNodeInfoAsync(param); + + var validTimeoutTo = DateTime.UtcNow.AddSeconds(20); + + Assert.NotNull(result); + + Assert.Equal(NodeState.Online, result.State); + + Assert.Equal(2, result.Addresses.Count); + Assert.Equal("address1", result.Addresses.ElementAt(0)); + Assert.Equal("address2", result.Addresses.ElementAt(1)); + + Assert.Equal(2, result.Attributes.Count); + Assert.Equal("value1", result.Attributes["key1"]); + Assert.Equal("value2", result.Attributes["key2"]); + + if (useContext) + { + Assert.Single(Mocker.LocalNodeInfoRequest.MetaHeader.XHeaders); + Assert.Equal(param.XHeaders.Keys[0], Mocker.LocalNodeInfoRequest.MetaHeader.XHeaders.First().Key); + Assert.Equal(param.XHeaders[param.XHeaders.Keys[0]], Mocker.LocalNodeInfoRequest.MetaHeader.XHeaders.First().Value); + + Assert.Equal(Mocker.CancellationTokenSource.Token, Mocker.CancellationToken); + Assert.NotNull(Mocker.DateTime); + + Assert.True(Mocker.DateTime.Value >= validTimeoutFrom); + Assert.True(Mocker.DateTime.Value <= validTimeoutTo); + } + else + { + Assert.Empty(Mocker.LocalNodeInfoRequest.MetaHeader.XHeaders); + Assert.Null(Mocker.DateTime); + } + } +} \ No newline at end of file diff --git a/src/FrostFS.SDK.Tests/SessionTests.cs b/src/FrostFS.SDK.Tests/SessionTests.cs new file mode 100644 index 0000000..8b3dc1a --- /dev/null +++ b/src/FrostFS.SDK.Tests/SessionTests.cs @@ -0,0 +1,127 @@ +using FrostFS.SDK.ClientV2; +using FrostFS.SDK.ClientV2.Interfaces; +using FrostFS.SDK.ClientV2.Mappers.GRPC; +using FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap; +using FrostFS.SDK.ClientV2.Parameters; +using FrostFS.SDK.Cryptography; +using FrostFS.SDK.ModelsV2; +using FrostFS.SDK.ModelsV2.Netmap; +using Microsoft.Extensions.Options; +using System.Security.Cryptography; + +namespace FrostFS.SDK.Tests; + +public abstract class SessionTestsBase +{ + protected readonly string key = "KwHDAJ66o8FoLBjVbjP2sWBmgBMGjt7Vv4boA7xQrBoAYBE397Aq"; + + protected IOptions Settings { get; set; } + + + protected ECDsa ECDsaKey { get; set; } + protected OwnerId OwnerId { get; set; } + protected SessionMocker Mocker { get; set; } + + protected SessionTestsBase() + { + Settings = Options.Create(new SingleOwnerClientSettings + { + Key = key, + Host = "http://localhost:8080" + }); + + ECDsaKey = key.LoadWif(); + OwnerId = OwnerId.FromKey(ECDsaKey); + + Mocker = new SessionMocker(this.key) + { + PlacementPolicy = new PlacementPolicy(true, new Replica(1)), + Version = new ModelsV2.Version(2, 13) + }; + } + + protected IFrostFSClient GetClient() + { + return ClientV2.Client.GetTestInstance( + Settings, + null, + new NetworkMocker(this.key).GetMock().Object, + Mocker.GetMock().Object, + new ContainerMocker(this.key).GetMock().Object, + new ObjectMocker(this.key).GetMock().Object); + } +} + +public class SessionTest : SessionTestsBase +{ + [Theory] + [InlineData(false)] + [InlineData(true)] + public async void CreateSessionTest(bool useContext) + { + var exp = 100u; + var param = new PrmSessionCreate(exp); + + if (useContext) + { + param.XHeaders.Add("headerKey1", "headerValue1"); + param.Context = new Context + { + CancellationToken = Mocker.CancellationTokenSource.Token, + Timeout = TimeSpan.FromSeconds(20), + OwnerId = OwnerId, + Key = ECDsaKey, + Version = Mocker.Version + }; + } + + var validTimeoutFrom = DateTime.UtcNow.AddSeconds(20); + + var result = await GetClient().CreateSessionAsync(param); + + var validTimeoutTo = DateTime.UtcNow.AddSeconds(20); + + Assert.NotNull(result); + Assert.NotNull(result.Token); + + var session = new Session.SessionToken().Deserialize(result.Token); + + Assert.Equal(Mocker.SessionId, session.Body.Id); + Assert.Equal(Mocker.SessionKey, session.Body.SessionKey); + + Assert.Equal(OwnerId.ToMessage(), session.Body.OwnerId); + Assert.Equal(exp, session.Body.Lifetime.Exp); + Assert.Equal(exp, session.Body.Lifetime.Iat); + Assert.Equal(exp, session.Body.Lifetime.Nbf); + Assert.Null(session.Body.Container); + + Assert.NotNull(Mocker.CreateSessionRequest); + + Assert.Equal(OwnerId.ToMessage(), Mocker.CreateSessionRequest.Body.OwnerId); + Assert.Equal(exp, Mocker.CreateSessionRequest.Body.Expiration); + Assert.NotNull(Mocker.CreateSessionRequest.MetaHeader); + Assert.Equal(Mocker.Version.ToMessage(), Mocker.CreateSessionRequest.MetaHeader.Version); + + + Assert.Null(Mocker.Metadata); + + if (useContext) + { + Assert.Single(Mocker.CreateSessionRequest.MetaHeader.XHeaders); + Assert.Equal(param.XHeaders.Keys[0], Mocker.CreateSessionRequest.MetaHeader.XHeaders.First().Key); + Assert.Equal(param.XHeaders[param.XHeaders.Keys[0]], Mocker.CreateSessionRequest.MetaHeader.XHeaders.First().Value); + + Assert.Equal(Mocker.CancellationTokenSource.Token, Mocker.CancellationToken); + Assert.NotNull(Mocker.DateTime); + + Assert.True(Mocker.DateTime.Value >= validTimeoutFrom); + Assert.True(Mocker.DateTime.Value <= validTimeoutTo); + Assert.True(validTimeoutTo.Ticks >= Mocker.DateTime.Value.Ticks); + } + else + { + Assert.Empty(Mocker.CreateSessionRequest.MetaHeader.XHeaders); + Assert.Null(Mocker.DateTime); + } + } +} \ No newline at end of file