frostfs-sdk-csharp/src/FrostFS.SDK.Tests/ClientTestLive.cs
Pavel Gross ae67b12313 [#14] Add interceptors
Signed-off-by: Pavel Gross <p.gross@yadro.com>
2024-07-01 15:11:52 +03:00

284 lines
8.4 KiB
C#

using System.Security.Cryptography;
using FrostFS.SDK.ClientV2;
using FrostFS.SDK.ClientV2.Interfaces;
using FrostFS.SDK.ModelsV2;
using FrostFS.SDK.ModelsV2.Enums;
using FrostFS.SDK.ModelsV2.Netmap;
using Grpc.Core;
using Grpc.Net.Client;
using Microsoft.Extensions.Options;
using Grpc.Core.Interceptors;
using System.Diagnostics;
namespace FrostFS.SDK.Tests;
public class ClientTestLive
{
private readonly string key = "KwHDAJ66o8FoLBjVbjP2sWBmgBMGjt7Vv4boA7xQrBoAYBE397Aq";
private readonly string url = "http://172.29.238.97:8080";
[Fact]
public async void NetworkMapTest()
{
using var fsClient = Client.GetInstance(GetOptions(this.key, this.url));
var result = await fsClient.GetNetmapSnapshotAsync();
Assert.True(result.Epoch > 0);
Assert.Single(result.NodeInfoCollection);
var item = result.NodeInfoCollection[0];
Assert.Equal(2, item.Version.Major);
Assert.Equal(13, item.Version.Minor);
Assert.Equal(NodeState.Online, item.State);
Assert.True(item.PublicKey.Length > 0);
Assert.Single(item.Addresses);
Assert.Equal(9, item.Attributes.Count);
}
[Fact]
public async void NodeInfoTest()
{
using var fsClient = Client.GetInstance(GetOptions(this.key, this.url));
var result = await fsClient.GetNodeInfoAsync();
Assert.Equal(2, result.Version.Major);
Assert.Equal(13, result.Version.Minor);
Assert.Equal(NodeState.Online, result.State);
Assert.True(result.PublicKey.Length > 0);
Assert.Single(result.Addresses);
Assert.Equal(9, result.Attributes.Count);
}
[Fact]
public async void SimpleScenarioTest()
{
using var fsClient = Client.GetInstance(GetOptions(this.key, this.url));
await Cleanup(fsClient);
var containerId = await fsClient.CreateContainerAsync(
new ModelsV2.Container(BasicAcl.PublicRW, new PlacementPolicy(true, new Replica(1))),
new Context
{
Callback = new((CallStatistics cs) => Assert.True(cs.ElapsedMicroSeconds > 0))
}
);
var context = new Context
{
Timeout = TimeSpan.FromSeconds(10),
Callback = new((CallStatistics cs) => Assert.True(cs.ElapsedMicroSeconds > 0))
};
var container = await GetContainer(fsClient, containerId, context);
Assert.NotNull(container);
Random rnd = new();
var bytes = new byte[6 * 1024 * 1024 + 100];
rnd.NextBytes(bytes);
var param = new PutObjectParameters
{
Header = new ObjectHeader(
containerId: containerId,
type: ObjectType.Regular,
new ObjectAttribute("fileName", "test")),
Payload = new MemoryStream(bytes),
ClientCut = false
};
var objectId = await fsClient.PutObjectAsync(param, new Context
{
Callback = new((CallStatistics cs) => Assert.True(cs.ElapsedMicroSeconds > 0))
});
var filter = new ObjectFilter(ObjectMatchType.Equals, "fileName", "test");
bool hasObject = false;
await foreach (var objId in fsClient.SearchObjectsAsync(containerId, [filter]))
{
hasObject = true;
var objHeader = await fsClient.GetObjectHeadAsync(containerId, objectId);
Assert.Equal((ulong)bytes.Length, objHeader.PayloadLength);
Assert.Single(objHeader.Attributes);
Assert.Equal("fileName", objHeader.Attributes.First().Key);
Assert.Equal("test", objHeader.Attributes.First().Value);
}
Assert.True(hasObject);
var @object = await fsClient.GetObjectAsync(containerId, objectId!);
var downloadedBytes = new byte[@object.Header.PayloadLength];
MemoryStream ms = new(downloadedBytes);
byte[]? chunk = null;
while ((chunk = await @object.ObjectReader!.ReadChunk()) != null)
{
ms.Write(chunk);
}
Assert.Equal(MD5.HashData(bytes), MD5.HashData(downloadedBytes));
await Cleanup(fsClient);
await Task.Delay(2000);
await foreach (var _ in fsClient.ListContainersAsync())
{
Assert.Fail("Containers exist");
}
}
[Fact]
public async void ClientCutScenarioTest()
{
using var fsClient = Client.GetInstance(GetOptions(this.key, this.url));
await Cleanup(fsClient);
var containerId = await fsClient.CreateContainerAsync(
new ModelsV2.Container(BasicAcl.PublicRW, new PlacementPolicy(true, new Replica(1))));
var context = new Context
{
Timeout = TimeSpan.FromSeconds(10)
};
var metrics = new MetricsInterceptor();
context.Interceptors.Add(metrics);
var container = await GetContainer(fsClient, containerId, context);
Assert.NotNull(container);
Random rnd = new();
var bytes = new byte[6 * 1024 * 1024 + 100];
rnd.NextBytes(bytes);
var param = new PutObjectParameters
{
Header = new ObjectHeader(
containerId: containerId,
type: ObjectType.Regular,
new ObjectAttribute("fileName", "test")),
Payload = new MemoryStream(bytes),
ClientCut = true
};
var objectId = await fsClient.PutObjectAsync(param);
var filter = new ObjectFilter(ObjectMatchType.Equals, "fileName", "test");
bool hasObject = false;
await foreach (var objId in fsClient.SearchObjectsAsync(containerId, [filter]))
{
hasObject = true;
var objHeader = await fsClient.GetObjectHeadAsync(containerId, objectId);
Assert.Equal((ulong)bytes.Length, objHeader.PayloadLength);
Assert.Single(objHeader.Attributes);
Assert.Equal("fileName", objHeader.Attributes.First().Key);
Assert.Equal("test", objHeader.Attributes.First().Value);
}
Assert.True(hasObject);
var @object = await fsClient.GetObjectAsync(containerId, objectId!);
var downloadedBytes = new byte[@object.Header.PayloadLength];
MemoryStream ms = new(downloadedBytes);
byte[]? chunk = null;
while ((chunk = await @object.ObjectReader!.ReadChunk()) != null)
{
ms.Write(chunk);
}
await Cleanup(fsClient);
await Task.Delay(2000);
await foreach (var _ in fsClient.ListContainersAsync())
{
Assert.Fail("Containers exist");
}
}
private static IOptions<ClientSettings> GetOptions(string key, string url)
{
var settings = new ClientSettings
{
Key = key,
Host = url
};
return Options.Create(settings);
}
static async Task Cleanup(IFrostFSClient fsClient)
{
await foreach (var cid in fsClient.ListContainersAsync())
{
await fsClient.DeleteContainerAsync(cid);
}
}
static async Task<ModelsV2.Container> GetContainer(IFrostFSClient fsClient, ContainerId id, Context ctx)
{
while (true)
{
try
{
await Task.Delay(100);
return await fsClient.GetContainerAsync(id, ctx);
}
catch (ApplicationException)
{
if (DateTime.UtcNow >= ctx.Deadline)
throw new TimeoutException();
}
catch (Grpc.Core.RpcException)
{
throw;
}
}
}
}
public class MetricsInterceptor() : Interceptor
{
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(
TRequest request,
ClientInterceptorContext<TRequest, TResponse> context,
AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
{
var call = continuation(request, context);
return new AsyncUnaryCall<TResponse>(
HandleUnaryResponse(call),
call.ResponseHeadersAsync,
call.GetStatus,
call.GetTrailers,
call.Dispose);
}
private async Task<TResponse> HandleUnaryResponse<TResponse>(AsyncUnaryCall<TResponse> call)
{
var watch = new Stopwatch();
watch.Start();
var response = await call.ResponseAsync;
watch.Stop();
var elapsed = watch.ElapsedTicks * 1_000_000/Stopwatch.Frequency;
return response;
}
}