using FrostFS.Netmap; using FrostFS.SDK.ClientV2; using FrostFS.SDK.ClientV2.Interfaces; using FrostFS.SDK.ClientV2; using FrostFS.SDK.Cryptography; using Google.Protobuf; using Microsoft.Extensions.Options; using System.Security.Cryptography; namespace FrostFS.SDK.Tests; public abstract class NetworkTestsBase { protected readonly string key = "KwHDAJ66o8FoLBjVbjP2sWBmgBMGjt7Vv4boA7xQrBoAYBE397Aq"; protected IOptions Settings { get; set; } protected FrostFsVersion Version { get; set; } = new FrostFsVersion(2, 13); protected ECDsa ECDsaKey { get; set; } protected FrostFsOwner 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 = FrostFsOwner.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); } } }