[#28] Client: Use external GRPC Channnel

Signed-off-by: Pavel Gross <p.gross@yadro.com>
This commit is contained in:
Pavel Gross 2024-12-06 09:01:33 +03:00
parent 9bb7b5eff8
commit c9418a1894
27 changed files with 520 additions and 438 deletions

View file

@ -4,8 +4,13 @@ using Google.Protobuf;
namespace FrostFS.SDK.Cryptography; namespace FrostFS.SDK.Cryptography;
public static class UUIDExtension public static class FrostFsExtensions
{ {
public static ByteString Sha256(this IMessage data)
{
return ByteString.CopyFrom(data.ToByteArray().Sha256());
}
public static Guid ToUuid(this ByteString id) public static Guid ToUuid(this ByteString id)
{ {
if (id == null) if (id == null)

View file

@ -15,21 +15,25 @@
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors> <CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>
</PropertyGroup> </PropertyGroup>
<PropertyGroup>
<_SkipUpgradeNetAnalyzersNuGetWarning>true</_SkipUpgradeNetAnalyzersNuGetWarning>
</PropertyGroup>
<PropertyGroup> <PropertyGroup>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild> <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" /> <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="7.0.0" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0"> <PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="7.0.4">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.1" /> <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.2" /> <PackageReference Include="Microsoft.Extensions.Options" Version="7.0.1" />
<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="8.0.1" /> <PackageReference Include="System.Diagnostics.DiagnosticSource" Version="7.0.0" />
<PackageReference Include="System.Runtime.Caching" Version="8.0.1" /> <PackageReference Include="System.Runtime.Caching" Version="7.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -1,6 +1,5 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using Frostfs.V2.Ape; using Frostfs.V2.Ape;
@ -12,7 +11,6 @@ using FrostFS.Session;
using Grpc.Core; using Grpc.Core;
using Grpc.Core.Interceptors; using Grpc.Core.Interceptors;
using Grpc.Net.Client;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
@ -27,8 +25,6 @@ namespace FrostFS.SDK.Client;
public class FrostFSClient : IFrostFSClient public class FrostFSClient : IFrostFSClient
{ {
private bool isDisposed;
internal ContainerServiceClient? ContainerServiceClient { get; set; } internal ContainerServiceClient? ContainerServiceClient { get; set; }
internal ContainerServiceProvider? ContainerServiceProvider { get; set; } internal ContainerServiceProvider? ContainerServiceProvider { get; set; }
@ -49,9 +45,19 @@ public class FrostFSClient : IFrostFSClient
internal ClientContext ClientCtx { get; set; } internal ClientContext ClientCtx { get; set; }
public static IFrostFSClient GetInstance(IOptions<ClientSettings> clientOptions, GrpcChannelOptions? channelOptions = null) public static IFrostFSClient GetInstance(IOptions<ClientSettings> clientOptions, Func<string, ChannelBase> grpcChannelFactory)
{ {
return new FrostFSClient(clientOptions, channelOptions); if (clientOptions is null)
{
throw new ArgumentNullException(nameof(clientOptions));
}
if (grpcChannelFactory is null)
{
throw new ArgumentNullException(nameof(grpcChannelFactory));
}
return new FrostFSClient(clientOptions, grpcChannelFactory);
} }
/// <summary> /// <summary>
@ -66,7 +72,7 @@ public class FrostFSClient : IFrostFSClient
/// <returns></returns> /// <returns></returns>
public static IFrostFSClient GetTestInstance( public static IFrostFSClient GetTestInstance(
IOptions<ClientSettings> settings, IOptions<ClientSettings> settings,
GrpcChannelOptions? channelOptions, Func<string, ChannelBase> grpcChannelFactory,
NetmapServiceClient netmapService, NetmapServiceClient netmapService,
SessionServiceClient sessionService, SessionServiceClient sessionService,
ContainerServiceClient containerService, ContainerServiceClient containerService,
@ -77,12 +83,38 @@ public class FrostFSClient : IFrostFSClient
throw new ArgumentNullException(nameof(settings)); throw new ArgumentNullException(nameof(settings));
} }
return new FrostFSClient(settings, channelOptions, containerService, netmapService, sessionService, objectService); if (grpcChannelFactory is null)
{
throw new ArgumentNullException(nameof(grpcChannelFactory));
}
if (netmapService is null)
{
throw new ArgumentNullException(nameof(netmapService));
}
if (sessionService is null)
{
throw new ArgumentNullException(nameof(sessionService));
}
if (containerService is null)
{
throw new ArgumentNullException(nameof(containerService));
}
if (objectService is null)
{
throw new ArgumentNullException(nameof(objectService));
}
return new FrostFSClient(
settings, channel: grpcChannelFactory(settings.Value.Host), containerService, netmapService, sessionService, objectService);
} }
private FrostFSClient( private FrostFSClient(
IOptions<ClientSettings> settings, IOptions<ClientSettings> settings,
GrpcChannelOptions? channelOptions, ChannelBase channel,
ContainerServiceClient containerService, ContainerServiceClient containerService,
NetmapServiceClient netmapService, NetmapServiceClient netmapService,
SessionServiceClient sessionService, SessionServiceClient sessionService,
@ -99,7 +131,7 @@ public class FrostFSClient : IFrostFSClient
client: this, client: this,
key: new ClientKey(ecdsaKey), key: new ClientKey(ecdsaKey),
owner: FrostFsOwner.FromKey(ecdsaKey), owner: FrostFsOwner.FromKey(ecdsaKey),
channel: InitGrpcChannel(settings.Value.Host, channelOptions), channel: channel,
version: new FrostFsVersion(2, 13)) version: new FrostFsVersion(2, 13))
{ {
SessionCache = new SessionCache(0), SessionCache = new SessionCache(0),
@ -113,7 +145,7 @@ public class FrostFSClient : IFrostFSClient
ObjectServiceClient = objectService ?? throw new ArgumentNullException(nameof(objectService)); ObjectServiceClient = objectService ?? throw new ArgumentNullException(nameof(objectService));
} }
private FrostFSClient(IOptions<ClientSettings> settings, GrpcChannelOptions? channelOptions) private FrostFSClient(IOptions<ClientSettings> settings, Func<string, ChannelBase> grpcChannelFactory)
{ {
var clientSettings = (settings?.Value) ?? throw new ArgumentNullException(nameof(settings), "Options value must be initialized"); var clientSettings = (settings?.Value) ?? throw new ArgumentNullException(nameof(settings), "Options value must be initialized");
@ -121,13 +153,11 @@ public class FrostFSClient : IFrostFSClient
var ecdsaKey = clientSettings.Key.LoadWif(); var ecdsaKey = clientSettings.Key.LoadWif();
var channel = InitGrpcChannel(clientSettings.Host, channelOptions);
ClientCtx = new ClientContext( ClientCtx = new ClientContext(
this, this,
key: new ClientKey(ecdsaKey), key: new ClientKey(ecdsaKey),
owner: FrostFsOwner.FromKey(ecdsaKey), owner: FrostFsOwner.FromKey(ecdsaKey),
channel: channel, channel: grpcChannelFactory(settings.Value.Host),
version: new FrostFsVersion(2, 13)) version: new FrostFsVersion(2, 13))
{ {
SessionCache = new SessionCache(0), SessionCache = new SessionCache(0),
@ -145,7 +175,7 @@ public class FrostFSClient : IFrostFSClient
client: this, client: this,
key: new ClientKey(prm.Key), key: new ClientKey(prm.Key),
owner: FrostFsOwner.FromKey(prm.Key!), owner: FrostFsOwner.FromKey(prm.Key!),
channel: InitGrpcChannel(prm.Address, null), //prm.GrpcChannelOptions), channel: prm.GrpcChannelFactory(prm.Address),
version: new FrostFsVersion(2, 13)) version: new FrostFsVersion(2, 13))
{ {
SessionCache = cache, SessionCache = cache,
@ -154,21 +184,6 @@ public class FrostFSClient : IFrostFSClient
}; };
} }
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing && !isDisposed)
{
ClientCtx?.Dispose();
isDisposed = true;
}
}
#region ApeManagerImplementation #region ApeManagerImplementation
public Task<ReadOnlyMemory<byte>> AddChainAsync(PrmApeChainAdd args, CallContext ctx) public Task<ReadOnlyMemory<byte>> AddChainAsync(PrmApeChainAdd args, CallContext ctx)
{ {
@ -246,9 +261,14 @@ public class FrostFSClient : IFrostFSClient
return GetObjectService().GetRangeHashAsync(args, ctx); return GetObjectService().GetRangeHashAsync(args, ctx);
} }
public Task<FrostFsObjectId> PutObjectAsync(PrmObjectPut args, CallContext ctx) public Task<IObjectWriter> PutObjectAsync(PrmObjectPut args, CallContext ctx)
{ {
return GetObjectService().PutObjectAsync(args, ctx); return GetObjectService().PutStreamObjectAsync(args, ctx);
}
public Task<FrostFsObjectId> PutClientCutObjectAsync(PrmObjectClientCutPut args, CallContext ctx)
{
return GetObjectService().PutClientCutObjectAsync(args, ctx);
} }
public Task<FrostFsObjectId> PutSingleObjectAsync(PrmSingleObjectPut args, CallContext ctx) public Task<FrostFsObjectId> PutSingleObjectAsync(PrmSingleObjectPut args, CallContext ctx)
@ -308,9 +328,6 @@ public class FrostFSClient : IFrostFSClient
private CallInvoker? CreateInvoker() private CallInvoker? CreateInvoker()
{ {
if (isDisposed)
throw new FrostFsInvalidObjectException("Client is disposed.");
CallInvoker? callInvoker = null; CallInvoker? callInvoker = null;
if (ClientCtx.Interceptors != null) if (ClientCtx.Interceptors != null)
@ -441,27 +458,6 @@ public class FrostFSClient : IFrostFSClient
return ObjectServiceProvider; return ObjectServiceProvider;
} }
private static GrpcChannel InitGrpcChannel(string host, GrpcChannelOptions? channelOptions)
{
try
{
var uri = new Uri(host);
if (channelOptions != null)
return GrpcChannel.ForAddress(uri, channelOptions);
return GrpcChannel.ForAddress(uri, new GrpcChannelOptions
{
HttpHandler = new HttpClientHandler()
});
}
catch (UriFormatException e)
{
throw new ArgumentException($"Host '{host}' has invalid format. Error: {e.Message}");
}
}
public async Task<string?> Dial(CallContext ctx) public async Task<string?> Dial(CallContext ctx)
{ {
var service = GetAccouningService(); var service = GetAccouningService();
@ -474,9 +470,4 @@ public class FrostFSClient : IFrostFSClient
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public void Close()
{
Dispose();
}
} }

View file

@ -6,7 +6,7 @@ using Frostfs.V2.Ape;
namespace FrostFS.SDK.Client.Interfaces; namespace FrostFS.SDK.Client.Interfaces;
public interface IFrostFSClient : IDisposable public interface IFrostFSClient
{ {
#region Network #region Network
Task<FrostFsNetmapSnapshot> GetNetmapSnapshotAsync(CallContext ctx); Task<FrostFsNetmapSnapshot> GetNetmapSnapshotAsync(CallContext ctx);
@ -47,7 +47,9 @@ public interface IFrostFSClient : IDisposable
Task<ReadOnlyMemory<byte>[]> GetRangeHashAsync(PrmRangeHashGet args, CallContext ctx); Task<ReadOnlyMemory<byte>[]> GetRangeHashAsync(PrmRangeHashGet args, CallContext ctx);
Task<FrostFsObjectId> PutObjectAsync(PrmObjectPut args, CallContext ctx); Task<IObjectWriter> PutObjectAsync(PrmObjectPut args, CallContext ctx);
Task<FrostFsObjectId> PutClientCutObjectAsync(PrmObjectClientCutPut args, CallContext ctx);
Task<FrostFsObjectId> PutSingleObjectAsync(PrmSingleObjectPut args, CallContext ctx); Task<FrostFsObjectId> PutSingleObjectAsync(PrmSingleObjectPut args, CallContext ctx);
@ -63,6 +65,4 @@ public interface IFrostFSClient : IDisposable
#endregion #endregion
public Task<string?> Dial(CallContext ctx); public Task<string?> Dial(CallContext ctx);
public void Close();
} }

View file

@ -0,0 +1,12 @@
using System;
using System.Threading.Tasks;
namespace FrostFS.SDK.Client.Interfaces
{
public interface IObjectWriter : IDisposable
{
Task WriteAsync(ReadOnlyMemory<byte> memory);
Task<FrostFsObjectId> CompleteAsync();
}
}

View file

@ -0,0 +1,68 @@
using System;
using System.Threading.Tasks;
using FrostFS.Object;
using FrostFS.SDK.Client.Interfaces;
using Google.Protobuf;
namespace FrostFS.SDK.Client
{
internal sealed class ObjectWriter : IObjectWriter
{
private readonly ClientContext ctx;
private readonly PrmObjectPutBase args;
private readonly ObjectStreamer<PutRequest, PutResponse> streamer;
private bool disposedValue;
internal ObjectWriter(ClientContext ctx, PrmObjectPutBase args, ObjectStreamer<PutRequest, PutResponse> streamer)
{
this.ctx = ctx;
this.args = args;
this.streamer = streamer;
}
public async Task WriteAsync(ReadOnlyMemory<byte> memory)
{
var chunkRequest = new PutRequest
{
Body = new PutRequest.Types.Body
{
Chunk = UnsafeByteOperations.UnsafeWrap(memory)
}
};
chunkRequest.Sign(this.ctx.Key.ECDsaKey);
await streamer.Write(chunkRequest).ConfigureAwait(false);
}
public async Task<FrostFsObjectId> CompleteAsync()
{
var response = await streamer.Close().ConfigureAwait(false);
Verifier.CheckResponse(response);
return FrostFsObjectId.FromHash(response.Body.ObjectId.Value.Span);
}
private void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
streamer.Dispose();
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
}

View file

@ -0,0 +1,78 @@
using System.IO;
namespace FrostFS.SDK.Client;
public readonly struct PrmObjectClientCutPut(
FrostFsObjectHeader? header,
Stream? payload,
int bufferMaxSize = 0,
FrostFsSessionToken? sessionToken = null,
byte[]? customBuffer = null,
string[]? xheaders = null) : PrmObjectPutBase, System.IEquatable<PrmObjectClientCutPut>
{
/// <summary>
/// Need to provide values like <c>ContainerId</c> and <c>ObjectType</c> to create and object.
/// Optional parameters ike <c>Attributes</c> can be provided as well.
/// </summary>
/// <value>Header with required parameters to create an object</value>
public FrostFsObjectHeader? Header { get; } = header;
/// <summary>
/// A stream with source data
/// </summary>
public Stream? Payload { get; } = payload;
/// <summary>
/// Overrides default size of the buffer for stream transferring.
/// </summary>
/// <value>Size of the buffer</value>
public int BufferMaxSize { get; } = bufferMaxSize;
/// <summary>
/// Allows to define a buffer for chunks to manage by the memory allocation and releasing.
/// </summary>
public byte[]? CustomBuffer { get; } = customBuffer;
/// <inheritdoc />
public FrostFsSessionToken? SessionToken { get; } = sessionToken;
/// <summary>
/// FrostFS request X-Headers
/// </summary>
public string[] XHeaders { get; } = xheaders ?? [];
internal PutObjectContext PutObjectContext { get; } = new();
public override readonly bool Equals(object obj)
{
if (obj == null || obj is not PrmObjectClientCutPut)
return false;
return Equals((PrmObjectClientCutPut)obj);
}
public readonly bool Equals(PrmObjectClientCutPut other)
{
return GetHashCode() == other.GetHashCode();
}
public override readonly int GetHashCode()
{
return BufferMaxSize
^ (Header == null ? 0 : Header.GetHashCode())
^ (Payload == null ? 0 : Payload.GetHashCode())
^ (CustomBuffer == null ? 0 : CustomBuffer.GetHashCode())
^ (SessionToken == null ? 0 : SessionToken.GetHashCode())
^ XHeaders.GetHashCode();
}
public static bool operator ==(PrmObjectClientCutPut left, PrmObjectClientCutPut right)
{
return left.Equals(right);
}
public static bool operator !=(PrmObjectClientCutPut left, PrmObjectClientCutPut right)
{
return !(left == right);
}
}

View file

@ -1,15 +1,17 @@
using System.IO;
namespace FrostFS.SDK.Client; namespace FrostFS.SDK.Client;
internal interface PrmObjectPutBase : ISessionToken
{
FrostFsObjectHeader? Header { get; }
string[] XHeaders { get; }
}
public readonly struct PrmObjectPut( public readonly struct PrmObjectPut(
FrostFsObjectHeader? header, FrostFsObjectHeader? header,
Stream? payload,
bool clientCut,
int bufferMaxSize = 0,
FrostFsSessionToken? sessionToken = null, FrostFsSessionToken? sessionToken = null,
byte[]? customBuffer = null, string[]? xheaders = null) : PrmObjectPutBase, System.IEquatable<PrmObjectPut>
string[]? xheaders = null) : ISessionToken, System.IEquatable<PrmObjectPut>
{ {
/// <summary> /// <summary>
/// Need to provide values like <c>ContainerId</c> and <c>ObjectType</c> to create and object. /// Need to provide values like <c>ContainerId</c> and <c>ObjectType</c> to create and object.
@ -18,30 +20,6 @@ public readonly struct PrmObjectPut(
/// <value>Header with required parameters to create an object</value> /// <value>Header with required parameters to create an object</value>
public FrostFsObjectHeader? Header { get; } = header; public FrostFsObjectHeader? Header { get; } = header;
/// <summary>
/// A stream with source data
/// </summary>
public Stream? Payload { get; } = payload;
/// <summary>
/// Object size is limited. In the data exceeds the limit, the object will be splitted.
/// If the parameter is <c>true</c>, the client side cut is applied. Otherwise, the data is transferred
/// as a stream and will be cut on server side.
/// </summary>
/// <value>Is client cut is applied</value>
public bool ClientCut { get; } = clientCut;
/// <summary>
/// Overrides default size of the buffer for stream transferring.
/// </summary>
/// <value>Size of the buffer</value>
public int BufferMaxSize { get; } = bufferMaxSize;
/// <summary>
/// Allows to define a buffer for chunks to manage by the memory allocation and releasing.
/// </summary>
public byte[]? CustomBuffer { get; } = customBuffer;
/// <inheritdoc /> /// <inheritdoc />
public FrostFsSessionToken? SessionToken { get; } = sessionToken; public FrostFsSessionToken? SessionToken { get; } = sessionToken;
@ -67,11 +45,7 @@ public readonly struct PrmObjectPut(
public override readonly int GetHashCode() public override readonly int GetHashCode()
{ {
return BufferMaxSize return (Header == null ? 0 : Header.GetHashCode())
^ (Header == null ? 0 : Header.GetHashCode())
^ (Payload == null ? 0 : Payload.GetHashCode())
^ (ClientCut ? 1 : 0)
^ (CustomBuffer == null ? 0 : CustomBuffer.GetHashCode())
^ (SessionToken == null ? 0 : SessionToken.GetHashCode()) ^ (SessionToken == null ? 0 : SessionToken.GetHashCode())
^ XHeaders.GetHashCode(); ^ XHeaders.GetHashCode();
} }

View file

@ -71,8 +71,6 @@ public class ClientWrapper : ClientStatusMonitor
return; return;
await Task.Delay((int)WrapperPrm.GracefulCloseOnSwitchTimeout).ConfigureAwait(false); await Task.Delay((int)WrapperPrm.GracefulCloseOnSwitchTimeout).ConfigureAwait(false);
Client.Close();
} }
// restartIfUnhealthy checks healthy status of client and recreate it if status is unhealthy. // restartIfUnhealthy checks healthy status of client and recreate it if status is unhealthy.
@ -98,13 +96,7 @@ public class ClientWrapper : ClientStatusMonitor
await ScheduleGracefulClose().ConfigureAwait(false); await ScheduleGracefulClose().ConfigureAwait(false);
} }
FrostFSClient? client = null; FrostFSClient? client = new(WrapperPrm, sessionCache);
try
{
client = new(WrapperPrm, sessionCache);
var dialCtx = new CallContext(TimeSpan.FromTicks((long)WrapperPrm.DialTimeout), ctx.CancellationToken);
var error = await client.Dial(ctx).ConfigureAwait(false); var error = await client.Dial(ctx).ConfigureAwait(false);
if (!string.IsNullOrEmpty(error)) if (!string.IsNullOrEmpty(error))
@ -118,13 +110,6 @@ public class ClientWrapper : ClientStatusMonitor
Client = client; Client = client;
} }
client = null;
}
finally
{
client?.Dispose();
}
try try
{ {
var res = await Client.GetNodeInfoAsync(ctx).ConfigureAwait(false); var res = await Client.GetNodeInfoAsync(ctx).ConfigureAwait(false);

View file

@ -2,6 +2,7 @@
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Security.Cryptography; using System.Security.Cryptography;
using Grpc.Core;
using Grpc.Core.Interceptors; using Grpc.Core.Interceptors;
using Grpc.Net.Client; using Grpc.Net.Client;
@ -10,7 +11,7 @@ using Microsoft.Extensions.Logging;
namespace FrostFS.SDK.Client; namespace FrostFS.SDK.Client;
// InitParameters contains values used to initialize connection Pool. // InitParameters contains values used to initialize connection Pool.
public class InitParameters public class InitParameters(Func<string, ChannelBase> grpcChannelFactory)
{ {
public ECDsa? Key { get; set; } public ECDsa? Key { get; set; }
@ -39,4 +40,6 @@ public class InitParameters
public Action<CallStatistics>? Callback { get; set; } public Action<CallStatistics>? Callback { get; set; }
public Collection<Interceptor> Interceptors { get; } = []; public Collection<Interceptor> Interceptors { get; } = [];
public Func<string, ChannelBase> GrpcChannelFactory { get; set; } = grpcChannelFactory;
} }

View file

@ -134,20 +134,20 @@ public partial class Pool : IFrostFSClient
int i = 0; int i = 0;
foreach (var nodeParams in RebalanceParams.NodesParams) foreach (var nodeParams in RebalanceParams.NodesParams)
{ {
var clients = new ClientWrapper[nodeParams.Weights.Count]; var wrappers = new ClientWrapper[nodeParams.Weights.Count];
for (int j = 0; j < nodeParams.Addresses.Count; j++) for (int j = 0; j < nodeParams.Addresses.Count; j++)
{ {
ClientWrapper? client = null; ClientWrapper? wrapper = null;
bool dialed = false; bool dialed = false;
try try
{ {
client = clients[j] = ClientBuilder(nodeParams.Addresses[j]); wrapper = wrappers[j] = ClientBuilder(nodeParams.Addresses[j]);
await client.Dial(ctx).ConfigureAwait(false); await wrapper.Dial(ctx).ConfigureAwait(false);
dialed = true; dialed = true;
var token = await InitSessionForDuration(ctx, client, RebalanceParams.SessionExpirationDuration, Key.ECDsaKey, false) var token = await InitSessionForDuration(ctx, wrapper, RebalanceParams.SessionExpirationDuration, Key.ECDsaKey, false)
.ConfigureAwait(false); .ConfigureAwait(false);
var key = FormCacheKey(nodeParams.Addresses[j], Key.PublicKey); var key = FormCacheKey(nodeParams.Addresses[j], Key.PublicKey);
@ -158,13 +158,13 @@ public partial class Pool : IFrostFSClient
catch (RpcException ex) catch (RpcException ex)
{ {
if (!dialed) if (!dialed)
client!.SetUnhealthyOnDial(); wrapper!.SetUnhealthyOnDial();
else else
client!.SetUnhealthy(); wrapper!.SetUnhealthy();
if (logger != null) if (logger != null)
{ {
FrostFsMessages.SessionCreationError(logger, client!.WrapperPrm.Address, ex.Message); FrostFsMessages.SessionCreationError(logger, wrapper!.WrapperPrm.Address, ex.Message);
} }
} }
catch (FrostFsInvalidObjectException) catch (FrostFsInvalidObjectException)
@ -175,7 +175,7 @@ public partial class Pool : IFrostFSClient
var sampler = new Sampler(nodeParams.Weights.ToArray()); var sampler = new Sampler(nodeParams.Weights.ToArray());
inner[i] = new InnerPool(sampler, clients); inner[i] = new InnerPool(sampler, wrappers);
i++; i++;
} }
@ -277,7 +277,7 @@ public partial class Pool : IFrostFSClient
parameters.ClientBuilder ??= new Func<string, ClientWrapper>((address) => parameters.ClientBuilder ??= new Func<string, ClientWrapper>((address) =>
{ {
var wrapperPrm = new WrapperPrm var wrapperPrm = new WrapperPrm()
{ {
Address = address, Address = address,
Key = parameters.Key!, Key = parameters.Key!,
@ -287,7 +287,9 @@ public partial class Pool : IFrostFSClient
ErrorThreshold = parameters.ErrorThreshold, ErrorThreshold = parameters.ErrorThreshold,
GracefulCloseOnSwitchTimeout = parameters.GracefulCloseOnSwitchTimeout, GracefulCloseOnSwitchTimeout = parameters.GracefulCloseOnSwitchTimeout,
Callback = parameters.Callback, Callback = parameters.Callback,
Interceptors = parameters.Interceptors Interceptors = parameters.Interceptors,
GrpcChannelFactory = parameters.GrpcChannelFactory
}; };
return new ClientWrapper(wrapperPrm, pool); return new ClientWrapper(wrapperPrm, pool);
@ -334,14 +336,14 @@ public partial class Pool : IFrostFSClient
{ {
CancellationTokenSource.Cancel(); CancellationTokenSource.Cancel();
if (InnerPools != null) //if (InnerPools != null)
{ //{
// close all clients // // close all clients
foreach (var innerPool in InnerPools) // foreach (var innerPool in InnerPools)
foreach (var client in innerPool.Clients) // foreach (var client in innerPool.Clients)
if (client.IsDialed()) // if (client.IsDialed())
client.Client?.Close(); // client.Client?.Close();
} //}
} }
// startRebalance runs loop to monitor connection healthy status. // startRebalance runs loop to monitor connection healthy status.
@ -586,12 +588,18 @@ public partial class Pool : IFrostFSClient
return await client.Client!.GetObjectAsync(args, ctx).ConfigureAwait(false); return await client.Client!.GetObjectAsync(args, ctx).ConfigureAwait(false);
} }
public async Task<FrostFsObjectId> PutObjectAsync(PrmObjectPut args, CallContext ctx) public async Task<IObjectWriter> PutObjectAsync(PrmObjectPut args, CallContext ctx)
{ {
var client = Connection(); var client = Connection();
return await client.Client!.PutObjectAsync(args, ctx).ConfigureAwait(false); return await client.Client!.PutObjectAsync(args, ctx).ConfigureAwait(false);
} }
public async Task<FrostFsObjectId> PutClientCutObjectAsync(PrmObjectClientCutPut args, CallContext ctx)
{
var client = Connection();
return await client.Client!.PutClientCutObjectAsync(args, ctx).ConfigureAwait(false);
}
public async Task<FrostFsObjectId> PutSingleObjectAsync(PrmSingleObjectPut args, CallContext ctx) public async Task<FrostFsObjectId> PutSingleObjectAsync(PrmSingleObjectPut args, CallContext ctx)
{ {
var client = Connection(); var client = Connection();
@ -655,8 +663,6 @@ public partial class Pool : IFrostFSClient
public void Dispose() public void Dispose()
{ {
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true); Dispose(disposing: true);
GC.SuppressFinalize(this);
} }
} }

View file

@ -2,8 +2,8 @@
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Security.Cryptography; using System.Security.Cryptography;
using Grpc.Core;
using Grpc.Core.Interceptors; using Grpc.Core.Interceptors;
using Grpc.Net.Client;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -28,7 +28,7 @@ public struct WrapperPrm
internal Action PoolRequestInfoCallback { get; set; } internal Action PoolRequestInfoCallback { get; set; }
internal GrpcChannelOptions GrpcChannelOptions { get; set; } internal Func<string, ChannelBase> GrpcChannelFactory { get; set; }
internal ulong GracefulCloseOnSwitchTimeout { get; set; } internal ulong GracefulCloseOnSwitchTimeout { get; set; }

View file

@ -8,6 +8,7 @@ using System.Threading.Tasks;
using FrostFS.Object; using FrostFS.Object;
using FrostFS.Refs; using FrostFS.Refs;
using FrostFS.SDK.Client; using FrostFS.SDK.Client;
using FrostFS.SDK.Client.Interfaces;
using FrostFS.SDK.Client.Mappers.GRPC; using FrostFS.SDK.Client.Mappers.GRPC;
using FrostFS.SDK.Cryptography; using FrostFS.SDK.Cryptography;
using FrostFS.Session; using FrostFS.Session;
@ -265,33 +266,6 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
} }
} }
internal async Task<FrostFsObjectId> PutObjectAsync(PrmObjectPut args, CallContext ctx)
{
if (args.Header == null)
throw new ArgumentNullException(nameof(args), "Header is null");
if (args.Payload == null)
throw new ArgumentNullException(nameof(args), "Payload is null");
if (args.ClientCut)
{
return await PutClientCutObject(args, ctx).ConfigureAwait(false);
}
else
{
if (args.Header.PayloadLength > 0)
args.PutObjectContext.FullLength = args.Header.PayloadLength;
else if (args.Payload.CanSeek)
args.PutObjectContext.FullLength = (ulong)args.Payload.Length;
else
throw new ArgumentException("The stream does not have a length and payload length is not defined");
var response = await PutStreamObject(args, ctx).ConfigureAwait(false);
return response.ObjectId;
}
}
internal async Task<FrostFsObjectId> PutSingleObjectAsync(PrmSingleObjectPut args, CallContext ctx) internal async Task<FrostFsObjectId> PutSingleObjectAsync(PrmSingleObjectPut args, CallContext ctx)
{ {
var grpcObject = ObjectTools.CreateObject(args.FrostFsObject, ClientContext); var grpcObject = ObjectTools.CreateObject(args.FrostFsObject, ClientContext);
@ -408,7 +382,7 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
return response.Body.ObjectId.ToModel(); return response.Body.ObjectId.ToModel();
} }
private async Task<FrostFsObjectId> PutClientCutObject(PrmObjectPut args, CallContext ctx) internal async Task<FrostFsObjectId> PutClientCutObjectAsync(PrmObjectClientCutPut args, CallContext ctx)
{ {
var payloadStream = args.Payload!; var payloadStream = args.Payload!;
var header = args.Header!; var header = args.Header!;
@ -451,7 +425,7 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
args.Header!.Split = split; args.Header!.Split = split;
var result = await PutStreamObject(args, default).ConfigureAwait(false); var result = await PutMultipartStreamObjectAsync(args, default).ConfigureAwait(false);
sentObjectIds.Add(result.ObjectId); sentObjectIds.Add(result.ObjectId);
@ -468,7 +442,7 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
args.Header.Split!.ParentHeader = largeObjectHeader; args.Header.Split!.ParentHeader = largeObjectHeader;
var result = await PutStreamObject(args, default).ConfigureAwait(false); var result = await PutMultipartStreamObjectAsync(args, default).ConfigureAwait(false);
sentObjectIds.Add(result.ObjectId); sentObjectIds.Add(result.ObjectId);
@ -484,7 +458,7 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
// We are here if the payload is placed to one Object. It means no cut action, just simple PUT. // We are here if the payload is placed to one Object. It means no cut action, just simple PUT.
args.Header!.Attributes = attributes; args.Header!.Attributes = attributes;
var singlePartResult = await PutStreamObject(args, default).ConfigureAwait(false); var singlePartResult = await PutMultipartStreamObjectAsync(args, default).ConfigureAwait(false);
return singlePartResult.ObjectId; return singlePartResult.ObjectId;
} }
@ -495,7 +469,7 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
public int ObjectSize = objectSize; public int ObjectSize = objectSize;
} }
private async Task<PutObjectResult> PutStreamObject(PrmObjectPut args, CallContext ctx) private async Task<PutObjectResult> PutMultipartStreamObjectAsync(PrmObjectClientCutPut args, CallContext ctx)
{ {
var payload = args.Payload!; var payload = args.Payload!;
@ -511,7 +485,7 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
try try
{ {
// 0 means no limit from client, so server side cut is performed // 0 means no limit from client, so server side cut is performed
var objectLimitSize = args.ClientCut ? args.PutObjectContext.MaxObjectSizeCache : 0; var objectLimitSize = args.PutObjectContext.MaxObjectSizeCache;
if (args.CustomBuffer != null) if (args.CustomBuffer != null)
{ {
@ -573,7 +547,14 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
} }
} }
private async Task<ObjectStreamer<PutRequest, PutResponse>> GetUploadStream(PrmObjectPut args, CallContext ctx) internal async Task<IObjectWriter> PutStreamObjectAsync(PrmObjectPutBase args, CallContext ctx)
{
var stream = await GetUploadStream(args, ctx).ConfigureAwait(false);
return new ObjectWriter(ClientContext, args, stream);
}
private async Task<ObjectStreamer<PutRequest, PutResponse>> GetUploadStream(PrmObjectPutBase args, CallContext ctx)
{ {
var header = args.Header!; var header = args.Header!;

View file

@ -1,12 +1,12 @@
using System; using System;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using Grpc.Core;
using Grpc.Core.Interceptors; using Grpc.Core.Interceptors;
using Grpc.Net.Client;
namespace FrostFS.SDK.Client; namespace FrostFS.SDK.Client;
public class ClientContext(FrostFSClient client, ClientKey key, FrostFsOwner owner, GrpcChannel channel, FrostFsVersion version) : IDisposable public class ClientContext(FrostFSClient client, ClientKey key, FrostFsOwner owner, ChannelBase channel, FrostFsVersion version)
{ {
private string? sessionKey; private string? sessionKey;
@ -14,7 +14,7 @@ public class ClientContext(FrostFSClient client, ClientKey key, FrostFsOwner own
internal string? Address { get; } = channel.Target; internal string? Address { get; } = channel.Target;
internal GrpcChannel Channel { get; private set; } = channel; internal ChannelBase Channel { get; private set; } = channel;
internal FrostFsVersion Version { get; } = version; internal FrostFsVersion Version { get; } = version;
@ -45,18 +45,4 @@ public class ClientContext(FrostFSClient client, ClientKey key, FrostFsOwner own
return sessionKey; return sessionKey;
} }
} }
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
Channel?.Dispose();
}
}
} }

View file

@ -1,8 +1,6 @@
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Threading; using System.Threading;
using Google.Protobuf;
using Org.BouncyCastle.Crypto.Digests; using Org.BouncyCastle.Crypto.Digests;
namespace FrostFS.SDK.Cryptography; namespace FrostFS.SDK.Cryptography;
@ -25,11 +23,6 @@ public static class Extentions
return hash; return hash;
} }
public static ByteString Sha256(this IMessage data)
{
return ByteString.CopyFrom(data.ToByteArray().Sha256());
}
public static byte[] Sha256(this byte[] value) public static byte[] Sha256(this byte[] value)
{ {
bool lockTaken = false; bool lockTaken = false;

View file

@ -10,14 +10,17 @@
<EnableNETAnalyzers>true</EnableNETAnalyzers> <EnableNETAnalyzers>true</EnableNETAnalyzers>
</PropertyGroup> </PropertyGroup>
<PropertyGroup>
<_SkipUpgradeNetAnalyzersNuGetWarning>true</_SkipUpgradeNetAnalyzersNuGetWarning>
</PropertyGroup>
<PropertyGroup> <PropertyGroup>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild> <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="BouncyCastle.Cryptography" Version="2.4.0" /> <PackageReference Include="BouncyCastle.Cryptography" Version="2.4.0" />
<PackageReference Include="Google.Protobuf" Version="3.21.12" /> <PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="7.0.4">
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

View file

@ -10,14 +10,18 @@
<EnableNETAnalyzers>true</EnableNETAnalyzers> <EnableNETAnalyzers>true</EnableNETAnalyzers>
</PropertyGroup> </PropertyGroup>
<PropertyGroup>
<_SkipUpgradeNetAnalyzersNuGetWarning>true</_SkipUpgradeNetAnalyzersNuGetWarning>
</PropertyGroup>
<PropertyGroup> <PropertyGroup>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild> <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.26.1" /> <PackageReference Include="Google.Protobuf" Version="3.21.12" />
<PackageReference Include="Grpc.Net.Client" Version="2.63.0" /> <PackageReference Include="Grpc.Net.Client" Version="2.63.0" />
<PackageReference Include="Grpc.Tools" Version="2.64.0"> <PackageReference Include="Grpc.Tools" Version="2.54.0">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

View file

@ -16,10 +16,9 @@ public class MultithreadPoolSmokeTests : SmokeTestsBase
private InitParameters GetDefaultParams() private InitParameters GetDefaultParams()
{ {
return new InitParameters return new InitParameters((url) => Grpc.Net.Client.GrpcChannel.ForAddress(new Uri(url)))
{ {
Key = keyString.LoadWif(), Key = keyString.LoadWif(),
NodeParams = [new(1, url, 100.0f)], NodeParams = [new(1, url, 100.0f)],
ClientBuilder = null, ClientBuilder = null,
GracefulCloseOnSwitchTimeout = 30_000_000, GracefulCloseOnSwitchTimeout = 30_000_000,
@ -32,7 +31,7 @@ public class MultithreadPoolSmokeTests : SmokeTestsBase
{ {
var options = GetDefaultParams(); var options = GetDefaultParams();
using var pool = new Pool(options); var pool = new Pool(options);
var error = await pool.Dial(new CallContext(TimeSpan.Zero)); var error = await pool.Dial(new CallContext(TimeSpan.Zero));
@ -57,7 +56,7 @@ public class MultithreadPoolSmokeTests : SmokeTestsBase
{ {
var options = GetDefaultParams(); var options = GetDefaultParams();
using var pool = new Pool(options); var pool = new Pool(options);
var error = await pool.Dial(new CallContext(TimeSpan.Zero)); var error = await pool.Dial(new CallContext(TimeSpan.Zero));
@ -78,7 +77,7 @@ public class MultithreadPoolSmokeTests : SmokeTestsBase
{ {
var callbackText = string.Empty; var callbackText = string.Empty;
var options = new InitParameters var options = new InitParameters((url) => Grpc.Net.Client.GrpcChannel.ForAddress(new Uri(url)))
{ {
Key = keyString.LoadWif(), Key = keyString.LoadWif(),
NodeParams = [ NodeParams = [
@ -91,7 +90,7 @@ public class MultithreadPoolSmokeTests : SmokeTestsBase
Callback = (cs) => callbackText = $"{cs.MethodName} took {cs.ElapsedMicroSeconds} microseconds" Callback = (cs) => callbackText = $"{cs.MethodName} took {cs.ElapsedMicroSeconds} microseconds"
}; };
using var pool = new Pool(options); var pool = new Pool(options);
var ctx = new CallContext(TimeSpan.Zero); var ctx = new CallContext(TimeSpan.Zero);
@ -99,9 +98,7 @@ public class MultithreadPoolSmokeTests : SmokeTestsBase
Assert.Null(error); Assert.Null(error);
using var client = FrostFSClient.GetInstance(GetSingleOwnerOptions(keyString, url)); var result = await pool.GetNodeInfoAsync(default);
var result = await client.GetNodeInfoAsync(default);
var statistics = pool.Statistic(); var statistics = pool.Statistic();
@ -117,7 +114,7 @@ public class MultithreadPoolSmokeTests : SmokeTestsBase
var callbackText = string.Empty; var callbackText = string.Empty;
options.Callback = (cs) => callbackText = $"{cs.MethodName} took {cs.ElapsedMicroSeconds} microseconds"; options.Callback = (cs) => callbackText = $"{cs.MethodName} took {cs.ElapsedMicroSeconds} microseconds";
using var pool = new Pool(options); var pool = new Pool(options);
var ctx = new CallContext(TimeSpan.Zero); var ctx = new CallContext(TimeSpan.Zero);
@ -125,9 +122,7 @@ public class MultithreadPoolSmokeTests : SmokeTestsBase
Assert.Null(error); Assert.Null(error);
using var client = FrostFSClient.GetInstance(GetSingleOwnerOptions(keyString, url)); var result = await pool.GetNodeInfoAsync(default);
var result = await client.GetNodeInfoAsync(default);
Assert.False(string.IsNullOrEmpty(callbackText)); Assert.False(string.IsNullOrEmpty(callbackText));
Assert.Contains(" took ", callbackText, StringComparison.Ordinal); Assert.Contains(" took ", callbackText, StringComparison.Ordinal);
@ -138,7 +133,7 @@ public class MultithreadPoolSmokeTests : SmokeTestsBase
{ {
var options = GetDefaultParams(); var options = GetDefaultParams();
using var pool = new Pool(options); var pool = new Pool(options);
var error = await pool.Dial(new CallContext(TimeSpan.Zero)).ConfigureAwait(true); var error = await pool.Dial(new CallContext(TimeSpan.Zero)).ConfigureAwait(true);
@ -160,7 +155,7 @@ public class MultithreadPoolSmokeTests : SmokeTestsBase
{ {
var options = GetDefaultParams(); var options = GetDefaultParams();
using var pool = new Pool(options); var pool = new Pool(options);
var error = await pool.Dial(new CallContext(TimeSpan.Zero)).ConfigureAwait(true); var error = await pool.Dial(new CallContext(TimeSpan.Zero)).ConfigureAwait(true);
@ -184,19 +179,19 @@ public class MultithreadPoolSmokeTests : SmokeTestsBase
containerId: containerId, containerId: containerId,
type: FrostFsObjectType.Regular, type: FrostFsObjectType.Regular,
[new FrostFsAttributePair("fileName", "test")]), [new FrostFsAttributePair("fileName", "test")]),
bufferMaxSize: 1024,
payload: new MemoryStream(bytes),
clientCut: false,
sessionToken: token); sessionToken: token);
var objectId = await pool.PutObjectAsync(param, default).ConfigureAwait(true); var stream = await pool.PutObjectAsync(param, default).ConfigureAwait(true);
await stream.WriteAsync(bytes.AsMemory());
var objectId = await stream.CompleteAsync();
var @object = await pool.GetObjectAsync(new PrmObjectGet(containerId, objectId), default); var @object = await pool.GetObjectAsync(new PrmObjectGet(containerId, objectId), default);
var downloadedBytes = new byte[@object.Header.PayloadLength]; var downloadedBytes = new byte[@object.Header.PayloadLength];
MemoryStream ms = new(downloadedBytes); MemoryStream ms = new(downloadedBytes);
ReadOnlyMemory<byte>? chunk = null; ReadOnlyMemory<byte>? chunk;
while ((chunk = await @object.ObjectReader!.ReadChunk()) != null) while ((chunk = await @object.ObjectReader!.ReadChunk()) != null)
{ {
ms.Write(chunk.Value.Span); ms.Write(chunk.Value.Span);
@ -212,7 +207,7 @@ public class MultithreadPoolSmokeTests : SmokeTestsBase
{ {
var options = GetDefaultParams(); var options = GetDefaultParams();
using var pool = new Pool(options); var pool = new Pool(options);
var error = await pool.Dial(new CallContext(TimeSpan.Zero)).ConfigureAwait(true); var error = await pool.Dial(new CallContext(TimeSpan.Zero)).ConfigureAwait(true);
@ -240,11 +235,12 @@ public class MultithreadPoolSmokeTests : SmokeTestsBase
containerId: containerId, containerId: containerId,
type: FrostFsObjectType.Regular, type: FrostFsObjectType.Regular,
[new FrostFsAttributePair("fileName", "test")], [new FrostFsAttributePair("fileName", "test")],
new FrostFsSplit()), new FrostFsSplit()));
payload: new MemoryStream(bytes),
clientCut: false);
var objectId = await pool.PutObjectAsync(param, default); var stream = await pool.PutObjectAsync(param, default).ConfigureAwait(true);
await stream.WriteAsync(bytes.AsMemory());
var objectId = await stream.CompleteAsync();
var head = await pool.GetObjectHeadAsync(new PrmObjectHeadGet(containerId, objectId, false), default); var head = await pool.GetObjectHeadAsync(new PrmObjectHeadGet(containerId, objectId, false), default);
@ -306,7 +302,7 @@ public class MultithreadPoolSmokeTests : SmokeTestsBase
Assert.True(cs.ElapsedMicroSeconds > 0); Assert.True(cs.ElapsedMicroSeconds > 0);
}); });
using var pool = new Pool(options); var pool = new Pool(options);
var error = await pool.Dial(new CallContext(TimeSpan.Zero)).ConfigureAwait(true); var error = await pool.Dial(new CallContext(TimeSpan.Zero)).ConfigureAwait(true);
@ -331,11 +327,12 @@ public class MultithreadPoolSmokeTests : SmokeTestsBase
new FrostFsObjectHeader( new FrostFsObjectHeader(
containerId: createdContainer, containerId: createdContainer,
type: FrostFsObjectType.Regular, type: FrostFsObjectType.Regular,
[new FrostFsAttributePair("fileName", "test")]), [new FrostFsAttributePair("fileName", "test")]));
payload: new MemoryStream(bytes),
clientCut: false);
var objectId = await pool.PutObjectAsync(param, default); var stream = await pool.PutObjectAsync(param, default).ConfigureAwait(true);
await stream.WriteAsync(bytes.AsMemory());
var objectId = await stream.CompleteAsync();
var filter = new FilterByAttributePair(FrostFsMatchType.Equals, "fileName", "test"); var filter = new FilterByAttributePair(FrostFsMatchType.Equals, "fileName", "test");
@ -385,7 +382,7 @@ public class MultithreadPoolSmokeTests : SmokeTestsBase
{ {
var options = GetDefaultParams(); var options = GetDefaultParams();
using var pool = new Pool(options); var pool = new Pool(options);
options.Callback = new((cs) => Assert.True(cs.ElapsedMicroSeconds > 0)); options.Callback = new((cs) => Assert.True(cs.ElapsedMicroSeconds > 0));
var error = await pool.Dial(new CallContext(TimeSpan.Zero)).ConfigureAwait(true); var error = await pool.Dial(new CallContext(TimeSpan.Zero)).ConfigureAwait(true);
@ -414,11 +411,12 @@ public class MultithreadPoolSmokeTests : SmokeTestsBase
containerId: container, containerId: container,
type: FrostFsObjectType.Regular, type: FrostFsObjectType.Regular,
[new FrostFsAttributePair("fileName", "test")]), [new FrostFsAttributePair("fileName", "test")]),
payload: new MemoryStream(bytes),
clientCut: false,
sessionToken: token); sessionToken: token);
var objectId = await pool.PutObjectAsync(param, default); var stream = await pool.PutObjectAsync(param, default).ConfigureAwait(true);
await stream.WriteAsync(bytes.AsMemory());
var objectId = await stream.CompleteAsync();
var filter = new FilterByAttributePair(FrostFsMatchType.Equals, "fileName", "test"); var filter = new FilterByAttributePair(FrostFsMatchType.Equals, "fileName", "test");
@ -472,7 +470,7 @@ public class MultithreadPoolSmokeTests : SmokeTestsBase
{ {
var options = GetDefaultParams(); var options = GetDefaultParams();
using var pool = new Pool(options); var pool = new Pool(options);
var error = await pool.Dial(new CallContext(TimeSpan.Zero)).ConfigureAwait(true); var error = await pool.Dial(new CallContext(TimeSpan.Zero)).ConfigureAwait(true);
@ -496,15 +494,14 @@ public class MultithreadPoolSmokeTests : SmokeTestsBase
byte[] bytes = GetRandomBytes(objectSize); byte[] bytes = GetRandomBytes(objectSize);
var param = new PrmObjectPut( var param = new PrmObjectClientCutPut(
new FrostFsObjectHeader( new FrostFsObjectHeader(
containerId: containerId, containerId: containerId,
type: FrostFsObjectType.Regular, type: FrostFsObjectType.Regular,
[new FrostFsAttributePair("fileName", "test")]), [new FrostFsAttributePair("fileName", "test")]),
payload: new MemoryStream(bytes), payload: new MemoryStream(bytes));
clientCut: true);
var objectId = await pool.PutObjectAsync(param, default); var objectId = await pool.PutClientCutObjectAsync(param, default).ConfigureAwait(true);
var filter = new FilterByAttributePair(FrostFsMatchType.Equals, "fileName", "test"); var filter = new FilterByAttributePair(FrostFsMatchType.Equals, "fileName", "test");

View file

@ -19,7 +19,7 @@ public class MultithreadSmokeClientTests : SmokeTestsBase
[Fact] [Fact]
public async void AccountTest() public async void AccountTest()
{ {
using var client = FrostFSClient.GetInstance(GetClientOptions(keyString, url)); var client = FrostFSClient.GetInstance(ClientOptions, GrpcChannel);
var result = await client.GetBalanceAsync(default); var result = await client.GetBalanceAsync(default);
@ -30,7 +30,7 @@ public class MultithreadSmokeClientTests : SmokeTestsBase
[Fact] [Fact]
public async void NetworkMapTest() public async void NetworkMapTest()
{ {
using var client = FrostFSClient.GetInstance(GetClientOptions(keyString, url)); var client = FrostFSClient.GetInstance(ClientOptions, GrpcChannel);
var result = await client.GetNetmapSnapshotAsync(default); var result = await client.GetNetmapSnapshotAsync(default);
@ -50,7 +50,7 @@ public class MultithreadSmokeClientTests : SmokeTestsBase
[Fact] [Fact]
public async void NodeInfoTest() public async void NodeInfoTest()
{ {
using var client = FrostFSClient.GetInstance(GetClientOptions(keyString, url)); var client = FrostFSClient.GetInstance(ClientOptions, GrpcChannel);
var result = await client.GetNodeInfoAsync(default); var result = await client.GetNodeInfoAsync(default);
@ -65,12 +65,12 @@ public class MultithreadSmokeClientTests : SmokeTestsBase
[Fact] [Fact]
public async void NodeInfoStatisticsTest() public async void NodeInfoStatisticsTest()
{ {
var options = GetClientOptions(keyString, url); var options = ClientOptions;
var callbackContent = string.Empty; var callbackContent = string.Empty;
options.Value.Callback = (cs) => callbackContent = $"{cs.MethodName} took {cs.ElapsedMicroSeconds} microseconds"; options.Value.Callback = (cs) => callbackContent = $"{cs.MethodName} took {cs.ElapsedMicroSeconds} microseconds";
using var client = FrostFSClient.GetInstance(options); var client = FrostFSClient.GetInstance(options, GrpcChannel);
var result = await client.GetNodeInfoAsync(default); var result = await client.GetNodeInfoAsync(default);
@ -80,12 +80,10 @@ public class MultithreadSmokeClientTests : SmokeTestsBase
[Fact] [Fact]
public async void GetSessionTest() public async void GetSessionTest()
{ {
using var client = FrostFSClient.GetInstance(GetClientOptions(keyString, url)); var client = FrostFSClient.GetInstance(ClientOptions, GrpcChannel);
var token = await client.CreateSessionAsync(new(100), default); var token = await client.CreateSessionAsync(new(100), default);
var ownerHash = Base58.Decode(OwnerId!.Value);
Assert.NotNull(token); Assert.NotNull(token);
Assert.NotEqual(Guid.Empty, token.Id); Assert.NotEqual(Guid.Empty, token.Id);
Assert.Equal(33, token.SessionKey.Length); Assert.Equal(33, token.SessionKey.Length);
@ -94,7 +92,7 @@ public class MultithreadSmokeClientTests : SmokeTestsBase
[Fact] [Fact]
public async void CreateObjectWithSessionToken() public async void CreateObjectWithSessionToken()
{ {
using var client = FrostFSClient.GetInstance(GetClientOptions(keyString, url)); var client = FrostFSClient.GetInstance(ClientOptions, GrpcChannel);
await Cleanup(client); await Cleanup(client);
@ -114,11 +112,12 @@ public class MultithreadSmokeClientTests : SmokeTestsBase
containerId: containerId, containerId: containerId,
type: FrostFsObjectType.Regular, type: FrostFsObjectType.Regular,
[new FrostFsAttributePair("fileName", "test")]), [new FrostFsAttributePair("fileName", "test")]),
payload: new MemoryStream(bytes),
clientCut: false,
sessionToken: token); sessionToken: token);
var objectId = await client.PutObjectAsync(param, default).ConfigureAwait(true); var stream = await client.PutObjectAsync(param, default).ConfigureAwait(true);
await stream.WriteAsync(bytes.AsMemory());
var objectId = await stream.CompleteAsync();
var @object = await client.GetObjectAsync(new PrmObjectGet(containerId, objectId), default) var @object = await client.GetObjectAsync(new PrmObjectGet(containerId, objectId), default)
.ConfigureAwait(true); .ConfigureAwait(true);
@ -140,7 +139,7 @@ public class MultithreadSmokeClientTests : SmokeTestsBase
[Fact] [Fact]
public async void FilterTest() public async void FilterTest()
{ {
using var client = FrostFSClient.GetInstance(GetClientOptions(keyString, url)); var client = FrostFSClient.GetInstance(ClientOptions, GrpcChannel);
await Cleanup(client); await Cleanup(client);
@ -164,11 +163,12 @@ public class MultithreadSmokeClientTests : SmokeTestsBase
containerId: containerId, containerId: containerId,
type: FrostFsObjectType.Regular, type: FrostFsObjectType.Regular,
[new FrostFsAttributePair("fileName", "test")], [new FrostFsAttributePair("fileName", "test")],
new FrostFsSplit()), new FrostFsSplit()));
payload: new MemoryStream(bytes),
clientCut: false);
var objectId = await client.PutObjectAsync(param, default); var stream = await client.PutObjectAsync(param, default).ConfigureAwait(true);
await stream.WriteAsync(bytes.AsMemory());
var objectId = await stream.CompleteAsync();
var head = await client.GetObjectHeadAsync(new PrmObjectHeadGet(containerId, objectId), default); var head = await client.GetObjectHeadAsync(new PrmObjectHeadGet(containerId, objectId), default);
@ -222,7 +222,7 @@ public class MultithreadSmokeClientTests : SmokeTestsBase
{ {
bool callbackInvoked = false; bool callbackInvoked = false;
var options = GetClientOptions(keyString, url); var options = ClientOptions;
options.Value.Callback = new((cs) => options.Value.Callback = new((cs) =>
{ {
@ -230,7 +230,7 @@ public class MultithreadSmokeClientTests : SmokeTestsBase
Assert.True(cs.ElapsedMicroSeconds > 0); Assert.True(cs.ElapsedMicroSeconds > 0);
}); });
using var client = FrostFSClient.GetInstance(options); var client = FrostFSClient.GetInstance(options, GrpcChannel);
await Cleanup(client); await Cleanup(client);
@ -253,11 +253,12 @@ public class MultithreadSmokeClientTests : SmokeTestsBase
new FrostFsObjectHeader( new FrostFsObjectHeader(
containerId: createdContainer, containerId: createdContainer,
type: FrostFsObjectType.Regular, type: FrostFsObjectType.Regular,
[new FrostFsAttributePair("fileName", "test")]), [new FrostFsAttributePair("fileName", "test")]));
payload: new MemoryStream(bytes),
clientCut: false);
var objectId = await client.PutObjectAsync(param, default); var stream = await client.PutObjectAsync(param, default).ConfigureAwait(true);
await stream.WriteAsync(bytes.AsMemory());
var objectId = await stream.CompleteAsync();
var filter = new FilterByAttributePair(FrostFsMatchType.Equals, "fileName", "test"); var filter = new FilterByAttributePair(FrostFsMatchType.Equals, "fileName", "test");
@ -302,7 +303,7 @@ public class MultithreadSmokeClientTests : SmokeTestsBase
[Fact] [Fact]
public async void PatchTest() public async void PatchTest()
{ {
using var client = FrostFSClient.GetInstance(GetClientOptions(keyString, url)); var client = FrostFSClient.GetInstance(ClientOptions, GrpcChannel);
await Cleanup(client); await Cleanup(client);
@ -326,11 +327,12 @@ public class MultithreadSmokeClientTests : SmokeTestsBase
new FrostFsObjectHeader( new FrostFsObjectHeader(
containerId: createdContainer, containerId: createdContainer,
type: FrostFsObjectType.Regular, type: FrostFsObjectType.Regular,
[new FrostFsAttributePair("fileName", "test")]), [new FrostFsAttributePair("fileName", "test")]));
payload: new MemoryStream(bytes),
clientCut: false);
var objectId = await client.PutObjectAsync(param, default); var stream = await client.PutObjectAsync(param, default).ConfigureAwait(true);
await stream.WriteAsync(bytes.AsMemory());
var objectId = await stream.CompleteAsync();
var patch = new byte[16]; var patch = new byte[16];
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
@ -381,7 +383,7 @@ public class MultithreadSmokeClientTests : SmokeTestsBase
[Fact] [Fact]
public async void RangeTest() public async void RangeTest()
{ {
using var client = FrostFSClient.GetInstance(GetClientOptions(keyString, url)); var client = FrostFSClient.GetInstance(ClientOptions, GrpcChannel);
await Cleanup(client); await Cleanup(client);
@ -402,11 +404,12 @@ public class MultithreadSmokeClientTests : SmokeTestsBase
} }
var param = new PrmObjectPut( var param = new PrmObjectPut(
new FrostFsObjectHeader(containerId: createdContainer, type: FrostFsObjectType.Regular), new FrostFsObjectHeader(containerId: createdContainer, type: FrostFsObjectType.Regular));
payload: new MemoryStream(bytes),
clientCut: false);
var objectId = await client.PutObjectAsync(param, default); var stream = await client.PutObjectAsync(param, default).ConfigureAwait(true);
await stream.WriteAsync(bytes.AsMemory());
var objectId = await stream.CompleteAsync();
var rangeParam = new PrmRangeGet(createdContainer, objectId, new FrostFsRange(100, 64)); var rangeParam = new PrmRangeGet(createdContainer, objectId, new FrostFsRange(100, 64));
@ -434,7 +437,7 @@ public class MultithreadSmokeClientTests : SmokeTestsBase
[Fact] [Fact]
public async void RangeHashTest() public async void RangeHashTest()
{ {
using var client = FrostFSClient.GetInstance(GetClientOptions(keyString, url)); var client = FrostFSClient.GetInstance(ClientOptions, GrpcChannel);
await Cleanup(client); await Cleanup(client);
@ -457,11 +460,12 @@ public class MultithreadSmokeClientTests : SmokeTestsBase
var param = new PrmObjectPut( var param = new PrmObjectPut(
new FrostFsObjectHeader( new FrostFsObjectHeader(
containerId: createdContainer, containerId: createdContainer,
type: FrostFsObjectType.Regular), type: FrostFsObjectType.Regular));
payload: new MemoryStream(bytes),
clientCut: false);
var objectId = await client.PutObjectAsync(param, default); var stream = await client.PutObjectAsync(param, default).ConfigureAwait(true);
await stream.WriteAsync(bytes.AsMemory());
var objectId = await stream.CompleteAsync();
var rangeParam = new PrmRangeHashGet(createdContainer, objectId, [new FrostFsRange(100, 64)], bytes); var rangeParam = new PrmRangeHashGet(createdContainer, objectId, [new FrostFsRange(100, 64)], bytes);
@ -486,7 +490,7 @@ public class MultithreadSmokeClientTests : SmokeTestsBase
[InlineData(6 * 1024 * 1024 + 100)] [InlineData(6 * 1024 * 1024 + 100)]
public async void SimpleScenarioWithSessionTest(int objectSize) public async void SimpleScenarioWithSessionTest(int objectSize)
{ {
using var client = FrostFSClient.GetInstance(GetClientOptions(keyString, url)); var client = FrostFSClient.GetInstance(ClientOptions, GrpcChannel);
//Callback = new((CallStatistics cs) => Assert.True(cs.ElapsedMicroSeconds > 0)) //Callback = new((CallStatistics cs) => Assert.True(cs.ElapsedMicroSeconds > 0))
var token = await client.CreateSessionAsync(new PrmSessionCreate(int.MaxValue), default); var token = await client.CreateSessionAsync(new PrmSessionCreate(int.MaxValue), default);
@ -510,11 +514,12 @@ public class MultithreadSmokeClientTests : SmokeTestsBase
containerId: container, containerId: container,
type: FrostFsObjectType.Regular, type: FrostFsObjectType.Regular,
[new FrostFsAttributePair("fileName", "test")]), [new FrostFsAttributePair("fileName", "test")]),
payload: new MemoryStream(bytes),
clientCut: false,
sessionToken: token); sessionToken: token);
var objectId = await client.PutObjectAsync(param, default); var stream = await client.PutObjectAsync(param, default).ConfigureAwait(true);
await stream.WriteAsync(bytes.AsMemory());
var objectId = await stream.CompleteAsync();
var filter = new FilterByAttributePair(FrostFsMatchType.Equals, "fileName", "test"); var filter = new FilterByAttributePair(FrostFsMatchType.Equals, "fileName", "test");
@ -567,11 +572,10 @@ public class MultithreadSmokeClientTests : SmokeTestsBase
[InlineData(200)] [InlineData(200)]
public async void ClientCutScenarioTest(int objectSize) public async void ClientCutScenarioTest(int objectSize)
{ {
var options = ClientOptions;
var options = GetClientOptions(keyString, url);
options.Value.Interceptors.Add(new CallbackInterceptor()); options.Value.Interceptors.Add(new CallbackInterceptor());
using var client = FrostFSClient.GetInstance(GetClientOptions(keyString, url)); var client = FrostFSClient.GetInstance(options, GrpcChannel);
await Cleanup(client); await Cleanup(client);
@ -589,15 +593,14 @@ public class MultithreadSmokeClientTests : SmokeTestsBase
byte[] bytes = GetRandomBytes(objectSize); byte[] bytes = GetRandomBytes(objectSize);
var param = new PrmObjectPut( var param = new PrmObjectClientCutPut(
new FrostFsObjectHeader( new FrostFsObjectHeader(
containerId: containerId, containerId: containerId,
type: FrostFsObjectType.Regular, type: FrostFsObjectType.Regular,
[new FrostFsAttributePair("fileName", "test")]), [new FrostFsAttributePair("fileName", "test")]),
payload: new MemoryStream(bytes), payload: new MemoryStream(bytes));
clientCut: true);
var objectId = await client.PutObjectAsync(param, default); var objectId = await client.PutClientCutObjectAsync(param, default).ConfigureAwait(true);
var filter = new FilterByAttributePair(FrostFsMatchType.Equals, "fileName", "test"); var filter = new FilterByAttributePair(FrostFsMatchType.Equals, "fileName", "test");
@ -659,7 +662,7 @@ public class MultithreadSmokeClientTests : SmokeTestsBase
bool callbackInvoked = false; bool callbackInvoked = false;
bool intercepterInvoked = false; bool intercepterInvoked = false;
var options = GetClientOptions(keyString, url); var options = ClientOptions;
options.Value.Callback = (cs) => options.Value.Callback = (cs) =>
{ {
callbackInvoked = true; callbackInvoked = true;
@ -668,7 +671,7 @@ public class MultithreadSmokeClientTests : SmokeTestsBase
options.Value.Interceptors.Add(new CallbackInterceptor(s => intercepterInvoked = true)); options.Value.Interceptors.Add(new CallbackInterceptor(s => intercepterInvoked = true));
using var client = FrostFSClient.GetInstance(options); var client = FrostFSClient.GetInstance(options, GrpcChannel);
var result = await client.GetNodeInfoAsync(default); var result = await client.GetNodeInfoAsync(default);

View file

@ -4,8 +4,6 @@ using System.Security.Cryptography;
using FrostFS.SDK.Client; using FrostFS.SDK.Client;
using FrostFS.SDK.Cryptography; using FrostFS.SDK.Cryptography;
using Microsoft.Extensions.Options;
namespace FrostFS.SDK.Tests.Smoke; namespace FrostFS.SDK.Tests.Smoke;
[SuppressMessage("Reliability", "CA2007:Consider calling ConfigureAwait on the awaited task", Justification = "Default Value is correct for tests")] [SuppressMessage("Reliability", "CA2007:Consider calling ConfigureAwait on the awaited task", Justification = "Default Value is correct for tests")]
@ -16,10 +14,9 @@ public class PoolSmokeTests : SmokeTestsBase
private InitParameters GetDefaultParams() private InitParameters GetDefaultParams()
{ {
return new InitParameters return new InitParameters((url) => Grpc.Net.Client.GrpcChannel.ForAddress(new Uri(url)))
{ {
Key = keyString.LoadWif(), Key = keyString.LoadWif(),
NodeParams = [new(1, url, 100.0f)], NodeParams = [new(1, url, 100.0f)],
ClientBuilder = null, ClientBuilder = null,
GracefulCloseOnSwitchTimeout = 30_000_000, GracefulCloseOnSwitchTimeout = 30_000_000,
@ -32,7 +29,7 @@ public class PoolSmokeTests : SmokeTestsBase
{ {
var options = GetDefaultParams(); var options = GetDefaultParams();
using var pool = new Pool(options); var pool = new Pool(options);
var error = await pool.Dial(new CallContext(TimeSpan.Zero)); var error = await pool.Dial(new CallContext(TimeSpan.Zero));
@ -57,7 +54,7 @@ public class PoolSmokeTests : SmokeTestsBase
{ {
var options = GetDefaultParams(); var options = GetDefaultParams();
using var pool = new Pool(options); var pool = new Pool(options);
var error = await pool.Dial(new CallContext(TimeSpan.Zero)); var error = await pool.Dial(new CallContext(TimeSpan.Zero));
@ -78,7 +75,7 @@ public class PoolSmokeTests : SmokeTestsBase
{ {
var callbackText = string.Empty; var callbackText = string.Empty;
var options = new InitParameters var options = new InitParameters((url) => Grpc.Net.Client.GrpcChannel.ForAddress(new Uri(url)))
{ {
Key = keyString.LoadWif(), Key = keyString.LoadWif(),
NodeParams = [ NodeParams = [
@ -91,7 +88,7 @@ public class PoolSmokeTests : SmokeTestsBase
Callback = (cs) => callbackText = $"{cs.MethodName} took {cs.ElapsedMicroSeconds} microseconds" Callback = (cs) => callbackText = $"{cs.MethodName} took {cs.ElapsedMicroSeconds} microseconds"
}; };
using var pool = new Pool(options); var pool = new Pool(options);
var ctx = new CallContext(TimeSpan.Zero); var ctx = new CallContext(TimeSpan.Zero);
@ -99,9 +96,7 @@ public class PoolSmokeTests : SmokeTestsBase
Assert.Null(error); Assert.Null(error);
using var client = FrostFSClient.GetInstance(GetSingleOwnerOptions(keyString, url)); var result = await pool.GetNodeInfoAsync(default);
var result = await client.GetNodeInfoAsync(default);
var statistics = pool.Statistic(); var statistics = pool.Statistic();
@ -117,7 +112,7 @@ public class PoolSmokeTests : SmokeTestsBase
var callbackText = string.Empty; var callbackText = string.Empty;
options.Callback = (cs) => callbackText = $"{cs.MethodName} took {cs.ElapsedMicroSeconds} microseconds"; options.Callback = (cs) => callbackText = $"{cs.MethodName} took {cs.ElapsedMicroSeconds} microseconds";
using var pool = new Pool(options); var pool = new Pool(options);
var ctx = new CallContext(TimeSpan.Zero); var ctx = new CallContext(TimeSpan.Zero);
@ -125,9 +120,7 @@ public class PoolSmokeTests : SmokeTestsBase
Assert.Null(error); Assert.Null(error);
using var client = FrostFSClient.GetInstance(GetSingleOwnerOptions(keyString, url)); var result = await pool.GetNodeInfoAsync(default);
var result = await client.GetNodeInfoAsync(default);
Assert.False(string.IsNullOrEmpty(callbackText)); Assert.False(string.IsNullOrEmpty(callbackText));
Assert.Contains(" took ", callbackText, StringComparison.Ordinal); Assert.Contains(" took ", callbackText, StringComparison.Ordinal);
@ -138,7 +131,7 @@ public class PoolSmokeTests : SmokeTestsBase
{ {
var options = GetDefaultParams(); var options = GetDefaultParams();
using var pool = new Pool(options); var pool = new Pool(options);
var error = await pool.Dial(new CallContext(TimeSpan.Zero)).ConfigureAwait(true); var error = await pool.Dial(new CallContext(TimeSpan.Zero)).ConfigureAwait(true);
@ -160,7 +153,7 @@ public class PoolSmokeTests : SmokeTestsBase
{ {
var options = GetDefaultParams(); var options = GetDefaultParams();
using var pool = new Pool(options); var pool = new Pool(options);
var error = await pool.Dial(new CallContext(TimeSpan.Zero)).ConfigureAwait(true); var error = await pool.Dial(new CallContext(TimeSpan.Zero)).ConfigureAwait(true);
@ -184,11 +177,12 @@ public class PoolSmokeTests : SmokeTestsBase
containerId: containerId, containerId: containerId,
type: FrostFsObjectType.Regular, type: FrostFsObjectType.Regular,
[new FrostFsAttributePair("fileName", "test")]), [new FrostFsAttributePair("fileName", "test")]),
payload: new MemoryStream(bytes),
clientCut: false,
sessionToken: token); sessionToken: token);
var objectId = await pool.PutObjectAsync(param, default).ConfigureAwait(true); var stream = await pool.PutObjectAsync(param, default).ConfigureAwait(true);
await stream.WriteAsync(bytes.AsMemory());
var objectId = await stream.CompleteAsync();
var @object = await pool.GetObjectAsync(new PrmObjectGet(containerId, objectId), default); var @object = await pool.GetObjectAsync(new PrmObjectGet(containerId, objectId), default);
@ -211,7 +205,7 @@ public class PoolSmokeTests : SmokeTestsBase
{ {
var options = GetDefaultParams(); var options = GetDefaultParams();
using var pool = new Pool(options); var pool = new Pool(options);
var error = await pool.Dial(new CallContext(TimeSpan.Zero)).ConfigureAwait(true); var error = await pool.Dial(new CallContext(TimeSpan.Zero)).ConfigureAwait(true);
@ -239,11 +233,12 @@ public class PoolSmokeTests : SmokeTestsBase
containerId: containerId, containerId: containerId,
type: FrostFsObjectType.Regular, type: FrostFsObjectType.Regular,
[new FrostFsAttributePair("fileName", "test")], [new FrostFsAttributePair("fileName", "test")],
new FrostFsSplit()), new FrostFsSplit()));
payload: new MemoryStream(bytes),
clientCut: false);
var objectId = await pool.PutObjectAsync(param, default); var stream = await pool.PutObjectAsync(param, default).ConfigureAwait(true);
await stream.WriteAsync(bytes.AsMemory());
var objectId = await stream.CompleteAsync();
var head = await pool.GetObjectHeadAsync(new PrmObjectHeadGet(containerId, objectId), default); var head = await pool.GetObjectHeadAsync(new PrmObjectHeadGet(containerId, objectId), default);
@ -305,7 +300,7 @@ public class PoolSmokeTests : SmokeTestsBase
Assert.True(cs.ElapsedMicroSeconds > 0); Assert.True(cs.ElapsedMicroSeconds > 0);
}); });
using var pool = new Pool(options); var pool = new Pool(options);
var error = await pool.Dial(new CallContext(TimeSpan.Zero)).ConfigureAwait(true); var error = await pool.Dial(new CallContext(TimeSpan.Zero)).ConfigureAwait(true);
@ -332,11 +327,12 @@ public class PoolSmokeTests : SmokeTestsBase
new FrostFsObjectHeader( new FrostFsObjectHeader(
containerId: createdContainer, containerId: createdContainer,
type: FrostFsObjectType.Regular, type: FrostFsObjectType.Regular,
[new FrostFsAttributePair("fileName", "test")]), [new FrostFsAttributePair("fileName", "test")]));
payload: new MemoryStream(bytes),
clientCut: false);
var objectId = await pool.PutObjectAsync(param, default); var stream = await pool.PutObjectAsync(param, default).ConfigureAwait(true);
await stream.WriteAsync(bytes.AsMemory());
var objectId = await stream.CompleteAsync();
var filter = new FilterByAttributePair(FrostFsMatchType.Equals, "fileName", "test"); var filter = new FilterByAttributePair(FrostFsMatchType.Equals, "fileName", "test");
@ -386,7 +382,7 @@ public class PoolSmokeTests : SmokeTestsBase
{ {
var options = GetDefaultParams(); var options = GetDefaultParams();
using var pool = new Pool(options); var pool = new Pool(options);
options.Callback = new((cs) => Assert.True(cs.ElapsedMicroSeconds > 0)); options.Callback = new((cs) => Assert.True(cs.ElapsedMicroSeconds > 0));
var error = await pool.Dial(new CallContext(TimeSpan.Zero)).ConfigureAwait(true); var error = await pool.Dial(new CallContext(TimeSpan.Zero)).ConfigureAwait(true);
@ -415,11 +411,12 @@ public class PoolSmokeTests : SmokeTestsBase
containerId: container, containerId: container,
type: FrostFsObjectType.Regular, type: FrostFsObjectType.Regular,
[new FrostFsAttributePair("fileName", "test")]), [new FrostFsAttributePair("fileName", "test")]),
payload: new MemoryStream(bytes),
clientCut: false,
sessionToken: token); sessionToken: token);
var objectId = await pool.PutObjectAsync(param, new CallContext(TimeSpan.Zero)); var stream = await pool.PutObjectAsync(param, new CallContext(TimeSpan.Zero)).ConfigureAwait(true);
await stream.WriteAsync(bytes.AsMemory());
var objectId = await stream.CompleteAsync();
var filter = new FilterByAttributePair(FrostFsMatchType.Equals, "fileName", "test"); var filter = new FilterByAttributePair(FrostFsMatchType.Equals, "fileName", "test");
@ -474,7 +471,7 @@ public class PoolSmokeTests : SmokeTestsBase
{ {
var options = GetDefaultParams(); var options = GetDefaultParams();
using var pool = new Pool(options); var pool = new Pool(options);
var error = await pool.Dial(new CallContext(TimeSpan.Zero)).ConfigureAwait(true); var error = await pool.Dial(new CallContext(TimeSpan.Zero)).ConfigureAwait(true);
@ -498,15 +495,14 @@ public class PoolSmokeTests : SmokeTestsBase
byte[] bytes = GetRandomBytes(objectSize); byte[] bytes = GetRandomBytes(objectSize);
var param = new PrmObjectPut( var param = new PrmObjectClientCutPut(
new FrostFsObjectHeader( new FrostFsObjectHeader(
containerId: containerId, containerId: containerId,
type: FrostFsObjectType.Regular, type: FrostFsObjectType.Regular,
[new FrostFsAttributePair("fileName", "test")]), [new FrostFsAttributePair("fileName", "test")]),
payload: new MemoryStream(bytes), payload: new MemoryStream(bytes));
clientCut: true);
var objectId = await pool.PutObjectAsync(param, default); var objectId = await pool.PutClientCutObjectAsync(param, default).ConfigureAwait(true);
var filter = new FilterByAttributePair(FrostFsMatchType.Equals, "fileName", "test"); var filter = new FilterByAttributePair(FrostFsMatchType.Equals, "fileName", "test");
@ -558,23 +554,6 @@ public class PoolSmokeTests : SmokeTestsBase
return bytes; return bytes;
} }
private static IOptions<ClientSettings> GetSingleOwnerOptions(string key, string url)
{
return Options.Create(new ClientSettings
{
Key = key,
Host = url
});
}
private static IOptions<ClientSettings> GetOptions(string url)
{
return Options.Create(new ClientSettings
{
Host = url
});
}
static async Task Cleanup(Pool pool) static async Task Cleanup(Pool pool)
{ {
await foreach (var cid in pool.ListContainersAsync(default, default)) await foreach (var cid in pool.ListContainersAsync(default, default))

View file

@ -19,7 +19,7 @@ public class SmokeClientTests : SmokeTestsBase
[Fact] [Fact]
public async void AccountTest() public async void AccountTest()
{ {
using var client = FrostFSClient.GetInstance(GetClientOptions(keyString, url)); var client = FrostFSClient.GetInstance(ClientOptions, GrpcChannel);
var result = await client.GetBalanceAsync(default); var result = await client.GetBalanceAsync(default);
@ -30,7 +30,7 @@ public class SmokeClientTests : SmokeTestsBase
[Fact] [Fact]
public async void NodeInfoTest() public async void NodeInfoTest()
{ {
using var client = FrostFSClient.GetInstance(GetClientOptions(keyString, url)); var client = FrostFSClient.GetInstance(ClientOptions, GrpcChannel);
var result = await client.GetNodeInfoAsync(default); var result = await client.GetNodeInfoAsync(default);
@ -45,12 +45,12 @@ public class SmokeClientTests : SmokeTestsBase
[Fact] [Fact]
public async void NodeInfoStatisticsTest() public async void NodeInfoStatisticsTest()
{ {
var options = GetClientOptions(keyString, url); var options = ClientOptions;
var callbackContent = string.Empty; var callbackContent = string.Empty;
options.Value.Callback = (cs) => callbackContent = $"{cs.MethodName} took {cs.ElapsedMicroSeconds} microseconds"; options.Value.Callback = (cs) => callbackContent = $"{cs.MethodName} took {cs.ElapsedMicroSeconds} microseconds";
using var client = FrostFSClient.GetInstance(options); var client = FrostFSClient.GetInstance(options, GrpcChannel);
var result = await client.GetNodeInfoAsync(default); var result = await client.GetNodeInfoAsync(default);
@ -60,7 +60,7 @@ public class SmokeClientTests : SmokeTestsBase
[Fact] [Fact]
public async void GetSessionTest() public async void GetSessionTest()
{ {
using var client = FrostFSClient.GetInstance(GetClientOptions(keyString, url)); var client = FrostFSClient.GetInstance(ClientOptions, GrpcChannel);
var token = await client.CreateSessionAsync(new(100), default); var token = await client.CreateSessionAsync(new(100), default);
@ -74,7 +74,7 @@ public class SmokeClientTests : SmokeTestsBase
[Fact] [Fact]
public async void CreateObjectWithSessionToken() public async void CreateObjectWithSessionToken()
{ {
using var client = FrostFSClient.GetInstance(GetClientOptions(keyString, url)); var client = FrostFSClient.GetInstance(ClientOptions, GrpcChannel);
await Cleanup(client); await Cleanup(client);
@ -94,11 +94,12 @@ public class SmokeClientTests : SmokeTestsBase
containerId: containerId, containerId: containerId,
type: FrostFsObjectType.Regular, type: FrostFsObjectType.Regular,
[new FrostFsAttributePair("fileName", "test")]), [new FrostFsAttributePair("fileName", "test")]),
payload: new MemoryStream(bytes),
clientCut: false,
sessionToken: token); sessionToken: token);
var objectId = await client.PutObjectAsync(param, default).ConfigureAwait(true); var stream = await client.PutObjectAsync(param, default).ConfigureAwait(true);
await stream.WriteAsync(bytes.AsMemory());
var objectId = await stream.CompleteAsync();
var @object = await client.GetObjectAsync(new PrmObjectGet(containerId, objectId), default) var @object = await client.GetObjectAsync(new PrmObjectGet(containerId, objectId), default)
.ConfigureAwait(true); .ConfigureAwait(true);
@ -120,7 +121,7 @@ public class SmokeClientTests : SmokeTestsBase
[Fact] [Fact]
public async void FilterTest() public async void FilterTest()
{ {
using var client = FrostFSClient.GetInstance(GetClientOptions(keyString, url)); var client = FrostFSClient.GetInstance(ClientOptions, GrpcChannel);
await Cleanup(client); await Cleanup(client);
@ -144,11 +145,12 @@ public class SmokeClientTests : SmokeTestsBase
containerId: containerId, containerId: containerId,
type: FrostFsObjectType.Regular, type: FrostFsObjectType.Regular,
[new FrostFsAttributePair("fileName", "test")], [new FrostFsAttributePair("fileName", "test")],
new FrostFsSplit()), new FrostFsSplit()));
payload: new MemoryStream(bytes),
clientCut: false);
var objectId = await client.PutObjectAsync(param, default); var stream = await client.PutObjectAsync(param, default).ConfigureAwait(true);
await stream.WriteAsync(bytes.AsMemory());
var objectId = await stream.CompleteAsync();
var head = await client.GetObjectHeadAsync(new PrmObjectHeadGet(containerId, objectId), default); var head = await client.GetObjectHeadAsync(new PrmObjectHeadGet(containerId, objectId), default);
@ -202,7 +204,7 @@ public class SmokeClientTests : SmokeTestsBase
{ {
bool callbackInvoked = false; bool callbackInvoked = false;
var options = GetClientOptions(keyString, url); var options = ClientOptions;
options.Value.Callback = new((cs) => options.Value.Callback = new((cs) =>
{ {
@ -210,7 +212,7 @@ public class SmokeClientTests : SmokeTestsBase
Assert.True(cs.ElapsedMicroSeconds > 0); Assert.True(cs.ElapsedMicroSeconds > 0);
}); });
using var client = FrostFSClient.GetInstance(options); var client = FrostFSClient.GetInstance(options, GrpcChannel);
await Cleanup(client); await Cleanup(client);
@ -233,11 +235,12 @@ public class SmokeClientTests : SmokeTestsBase
new FrostFsObjectHeader( new FrostFsObjectHeader(
containerId: createdContainer, containerId: createdContainer,
type: FrostFsObjectType.Regular, type: FrostFsObjectType.Regular,
[new FrostFsAttributePair("fileName", "test")]), [new FrostFsAttributePair("fileName", "test")]));
payload: new MemoryStream(bytes),
clientCut: false);
var objectId = await client.PutObjectAsync(param, default); var stream = await client.PutObjectAsync(param, default).ConfigureAwait(true);
await stream.WriteAsync(bytes.AsMemory());
var objectId = await stream.CompleteAsync();
var filter1 = new FilterByOwnerId(FrostFsMatchType.Equals, OwnerId!); var filter1 = new FilterByOwnerId(FrostFsMatchType.Equals, OwnerId!);
await foreach (var objId in client.SearchObjectsAsync(new PrmObjectSearch(createdContainer, null, [], filter1), default)) await foreach (var objId in client.SearchObjectsAsync(new PrmObjectSearch(createdContainer, null, [], filter1), default))
@ -292,7 +295,7 @@ public class SmokeClientTests : SmokeTestsBase
[Fact] [Fact]
public async void PatchTest() public async void PatchTest()
{ {
using var client = FrostFSClient.GetInstance(GetClientOptions(keyString, url)); var client = FrostFSClient.GetInstance(ClientOptions, GrpcChannel);
await Cleanup(client); await Cleanup(client);
@ -316,24 +319,25 @@ public class SmokeClientTests : SmokeTestsBase
new FrostFsObjectHeader( new FrostFsObjectHeader(
containerId: createdContainer, containerId: createdContainer,
type: FrostFsObjectType.Regular, type: FrostFsObjectType.Regular,
[new FrostFsAttributePair("fileName", "test")]), [new FrostFsAttributePair("fileName", "test")]));
payload: new MemoryStream(bytes),
clientCut: false);
var objectId = await client.PutObjectAsync(param, default); var stream = await client.PutObjectAsync(param, default).ConfigureAwait(true);
var patch = new byte[16]; await stream.WriteAsync(bytes.AsMemory());
for (int i = 0; i < 16; i++) var objectId = await stream.CompleteAsync();
var patch = new byte[256];
for (int i = 0; i < patch.Length; i++)
{ {
patch[i] = 32; patch[i] = 32;
} }
var range = new FrostFsRange(8, (ulong)patch.Length); var range = new FrostFsRange(64, (ulong)patch.Length);
var patchParams = new PrmObjectPatch( var patchParams = new PrmObjectPatch(
new FrostFsAddress(createdContainer, objectId), new FrostFsAddress(createdContainer, objectId),
payload: new MemoryStream(patch), payload: new MemoryStream(patch),
maxChunkLength: 32, maxChunkLength: 256,
range: range); range: range);
var newIbjId = await client.PatchObjectAsync(patchParams, default); var newIbjId = await client.PatchObjectAsync(patchParams, default);
@ -371,7 +375,7 @@ public class SmokeClientTests : SmokeTestsBase
[Fact] [Fact]
public async void RangeTest() public async void RangeTest()
{ {
using var client = FrostFSClient.GetInstance(GetClientOptions(keyString, url)); var client = FrostFSClient.GetInstance(ClientOptions, GrpcChannel);
await Cleanup(client); await Cleanup(client);
@ -394,26 +398,27 @@ public class SmokeClientTests : SmokeTestsBase
var param = new PrmObjectPut( var param = new PrmObjectPut(
new FrostFsObjectHeader( new FrostFsObjectHeader(
containerId: createdContainer, containerId: createdContainer,
type: FrostFsObjectType.Regular), type: FrostFsObjectType.Regular));
payload: new MemoryStream(bytes),
clientCut: false);
var objectId = await client.PutObjectAsync(param, default); var stream = await client.PutObjectAsync(param, default).ConfigureAwait(true);
var rangeParam = new PrmRangeGet(createdContainer, objectId, new FrostFsRange(100, 64)); await stream.WriteAsync(bytes.AsMemory());
var objectId = await stream.CompleteAsync();
var rangeParam = new PrmRangeGet(createdContainer, objectId, new FrostFsRange(50, 100));
var rangeReader = await client.GetRangeAsync(rangeParam, default); var rangeReader = await client.GetRangeAsync(rangeParam, default);
var downloadedBytes = new byte[rangeParam.Range.Length]; var downloadedBytes = new byte[rangeParam.Range.Length];
MemoryStream ms = new(downloadedBytes); MemoryStream ms = new(downloadedBytes);
ReadOnlyMemory<byte>? chunk = null; ReadOnlyMemory<byte>? chunk;
while ((chunk = await rangeReader!.ReadChunk()) != null) while ((chunk = await rangeReader!.ReadChunk()) != null)
{ {
ms.Write(chunk.Value.Span); ms.Write(chunk.Value.Span);
} }
Assert.Equal(SHA256.HashData(bytes.AsSpan().Slice(100, 64)), SHA256.HashData(downloadedBytes)); Assert.Equal(SHA256.HashData(bytes.AsSpan().Slice(50, 100)), SHA256.HashData(downloadedBytes));
await Cleanup(client); await Cleanup(client);
@ -426,7 +431,7 @@ public class SmokeClientTests : SmokeTestsBase
[Fact] [Fact]
public async void RangeHashTest() public async void RangeHashTest()
{ {
using var client = FrostFSClient.GetInstance(GetClientOptions(keyString, url)); var client = FrostFSClient.GetInstance(ClientOptions, GrpcChannel);
await Cleanup(client); await Cleanup(client);
@ -449,11 +454,12 @@ public class SmokeClientTests : SmokeTestsBase
var param = new PrmObjectPut( var param = new PrmObjectPut(
new FrostFsObjectHeader( new FrostFsObjectHeader(
containerId: createdContainer, containerId: createdContainer,
type: FrostFsObjectType.Regular), type: FrostFsObjectType.Regular));
payload: new MemoryStream(bytes),
clientCut: false);
var objectId = await client.PutObjectAsync(param, default); var stream = await client.PutObjectAsync(param, default).ConfigureAwait(true);
await stream.WriteAsync(bytes.AsMemory());
var objectId = await stream.CompleteAsync();
var rangeParam = new PrmRangeHashGet(createdContainer, objectId, [new FrostFsRange(100, 64)], bytes); var rangeParam = new PrmRangeHashGet(createdContainer, objectId, [new FrostFsRange(100, 64)], bytes);
@ -478,7 +484,7 @@ public class SmokeClientTests : SmokeTestsBase
[InlineData(6 * 1024 * 1024 + 100)] [InlineData(6 * 1024 * 1024 + 100)]
public async void SimpleScenarioWithSessionTest(int objectSize) public async void SimpleScenarioWithSessionTest(int objectSize)
{ {
using var client = FrostFSClient.GetInstance(GetClientOptions(keyString, url)); var client = FrostFSClient.GetInstance(ClientOptions, GrpcChannel);
//Callback = new((CallStatistics cs) => Assert.True(cs.ElapsedMicroSeconds > 0)) //Callback = new((CallStatistics cs) => Assert.True(cs.ElapsedMicroSeconds > 0))
var token = await client.CreateSessionAsync(new PrmSessionCreate(int.MaxValue), default); var token = await client.CreateSessionAsync(new PrmSessionCreate(int.MaxValue), default);
@ -502,11 +508,12 @@ public class SmokeClientTests : SmokeTestsBase
containerId: container, containerId: container,
type: FrostFsObjectType.Regular, type: FrostFsObjectType.Regular,
[new FrostFsAttributePair("fileName", "test")]), [new FrostFsAttributePair("fileName", "test")]),
payload: new MemoryStream(bytes),
clientCut: false,
sessionToken: token); sessionToken: token);
var objectId = await client.PutObjectAsync(param, default); var stream = await client.PutObjectAsync(param, default).ConfigureAwait(true);
await stream.WriteAsync(bytes.AsMemory());
var objectId = await stream.CompleteAsync();
var filter = new FilterByAttributePair(FrostFsMatchType.Equals, "fileName", "test"); var filter = new FilterByAttributePair(FrostFsMatchType.Equals, "fileName", "test");
@ -558,11 +565,10 @@ public class SmokeClientTests : SmokeTestsBase
[InlineData(200)] [InlineData(200)]
public async void ClientCutScenarioTest(int objectSize) public async void ClientCutScenarioTest(int objectSize)
{ {
var options = ClientOptions;
var options = GetClientOptions(keyString, url);
options.Value.Interceptors.Add(new CallbackInterceptor()); options.Value.Interceptors.Add(new CallbackInterceptor());
using var client = FrostFSClient.GetInstance(GetClientOptions(keyString, url)); var client = FrostFSClient.GetInstance(options, GrpcChannel);
await Cleanup(client); await Cleanup(client);
@ -580,15 +586,14 @@ public class SmokeClientTests : SmokeTestsBase
byte[] bytes = GetRandomBytes(objectSize); byte[] bytes = GetRandomBytes(objectSize);
var param = new PrmObjectPut( var param = new PrmObjectClientCutPut(
new FrostFsObjectHeader( new FrostFsObjectHeader(
containerId: containerId, containerId: containerId,
type: FrostFsObjectType.Regular, type: FrostFsObjectType.Regular,
[new FrostFsAttributePair("fileName", "test")]), [new FrostFsAttributePair("fileName", "test")]),
payload: new MemoryStream(bytes), payload: new MemoryStream(bytes));
clientCut: true);
var objectId = await client.PutObjectAsync(param, default); var objectId = await client.PutClientCutObjectAsync(param, default).ConfigureAwait(true);
// var filter = new FilterByAttributePair(FrostFsMatchType.Equals, "fileName", "test"); // var filter = new FilterByAttributePair(FrostFsMatchType.Equals, "fileName", "test");
@ -607,14 +612,12 @@ public class SmokeClientTests : SmokeTestsBase
//Assert.True(hasObject); //Assert.True(hasObject);
var filter1 = new FilterByOwnerId(FrostFsMatchType.Equals, OwnerId!); var filter1 = new FilterByOwnerId(FrostFsMatchType.Equals, OwnerId!);
await foreach (var objId in client.SearchObjectsAsync(new PrmObjectSearch(containerId, null, [], filter1), default)) await foreach (var objId in client.SearchObjectsAsync(new PrmObjectSearch(containerId, null, [], filter1), default))
{ {
var objHeader = await client.GetObjectHeadAsync(new PrmObjectHeadGet(containerId, objectId, false), default); var objHeader = await client.GetObjectHeadAsync(new PrmObjectHeadGet(containerId, objectId, false), default);
var objHeader1 = await client.GetObjectHeadAsync(new PrmObjectHeadGet(containerId, objectId, true), default); var objHeader1 = await client.GetObjectHeadAsync(new PrmObjectHeadGet(containerId, objectId, true), default);
} }
var @object = await client.GetObjectAsync(new PrmObjectGet(containerId, objectId), default); var @object = await client.GetObjectAsync(new PrmObjectGet(containerId, objectId), default);
@ -657,7 +660,7 @@ public class SmokeClientTests : SmokeTestsBase
bool callbackInvoked = false; bool callbackInvoked = false;
bool intercepterInvoked = false; bool intercepterInvoked = false;
var options = GetClientOptions(keyString, url); var options = ClientOptions;
options.Value.Callback = (cs) => options.Value.Callback = (cs) =>
{ {
callbackInvoked = true; callbackInvoked = true;
@ -666,7 +669,7 @@ public class SmokeClientTests : SmokeTestsBase
options.Value.Interceptors.Add(new CallbackInterceptor(s => intercepterInvoked = true)); options.Value.Interceptors.Add(new CallbackInterceptor(s => intercepterInvoked = true));
using var client = FrostFSClient.GetInstance(options); var client = FrostFSClient.GetInstance(options, GrpcChannel);
var result = await client.GetNodeInfoAsync(default); var result = await client.GetNodeInfoAsync(default);

View file

@ -3,6 +3,10 @@
using FrostFS.SDK.Client; using FrostFS.SDK.Client;
using FrostFS.SDK.Cryptography; using FrostFS.SDK.Cryptography;
using Grpc.Core;
using Microsoft.Extensions.Options;
namespace FrostFS.SDK.Tests.Smoke; namespace FrostFS.SDK.Tests.Smoke;
public abstract class SmokeTestsBase public abstract class SmokeTestsBase
@ -25,4 +29,8 @@ public abstract class SmokeTestsBase
OwnerId = FrostFsOwner.FromKey(Key); OwnerId = FrostFsOwner.FromKey(Key);
Version = new FrostFsVersion(2, 13); Version = new FrostFsVersion(2, 13);
} }
protected static Func<string, ChannelBase> GrpcChannel => (url) => Grpc.Net.Client.GrpcChannel.ForAddress(new Uri(url));
protected IOptions<ClientSettings> ClientOptions => Options.Create(new ClientSettings { Key = keyString, Host = url });
} }

View file

@ -31,7 +31,7 @@ public abstract class ContainerTestsBase
{ {
return Client.FrostFSClient.GetTestInstance( return Client.FrostFSClient.GetTestInstance(
Settings, Settings,
null, (url) => Grpc.Net.Client.GrpcChannel.ForAddress(new Uri(url)),
new NetworkMocker(key).GetMock().Object, new NetworkMocker(key).GetMock().Object,
new SessionMocker(key).GetMock().Object, new SessionMocker(key).GetMock().Object,
Mocker.GetMock().Object, Mocker.GetMock().Object,

View file

@ -32,7 +32,7 @@ public abstract class NetworkTestsBase
{ {
return Client.FrostFSClient.GetTestInstance( return Client.FrostFSClient.GetTestInstance(
Options.Create(settings), Options.Create(settings),
null, (url) => Grpc.Net.Client.GrpcChannel.ForAddress(new Uri(url)),
Mocker.GetMock().Object, Mocker.GetMock().Object,
new SessionMocker(key).GetMock().Object, new SessionMocker(key).GetMock().Object,
new ContainerMocker(key).GetMock().Object, new ContainerMocker(key).GetMock().Object,

View file

@ -24,12 +24,12 @@ public class ObjectTest : ObjectTestsBase
var bytes = new byte[1024]; var bytes = new byte[1024];
rnd.NextBytes(bytes); rnd.NextBytes(bytes);
var param = new PrmObjectPut( var param = new PrmObjectPut(Mocker.ObjectHeader);
Mocker.ObjectHeader,
payload: new MemoryStream(bytes),
clientCut: false);
var result = await GetClient().PutObjectAsync(param, default); var stream = await GetClient().PutObjectAsync(param, default).ConfigureAwait(true);
await stream.WriteAsync(bytes.AsMemory());
var result = await stream.CompleteAsync();
var sentMessages = Mocker.ClientStreamWriter!.Messages; var sentMessages = Mocker.ClientStreamWriter!.Messages;
@ -57,11 +57,10 @@ public class ObjectTest : ObjectTestsBase
byte[] bytes = File.ReadAllBytes(@".\..\..\..\cat.jpg"); byte[] bytes = File.ReadAllBytes(@".\..\..\..\cat.jpg");
var fileLength = bytes.Length; var fileLength = bytes.Length;
var param = new PrmObjectPut( var param = new PrmObjectClientCutPut(
Mocker.ObjectHeader, Mocker.ObjectHeader,
payload: new MemoryStream(bytes), payload: new MemoryStream(bytes),
bufferMaxSize: 1024, bufferMaxSize: 1024);
clientCut: true);
Random rnd = new(); Random rnd = new();
@ -73,7 +72,7 @@ public class ObjectTest : ObjectTestsBase
foreach (var objId in objIds) foreach (var objId in objIds)
Mocker.ResultObjectIds!.Add(objId); Mocker.ResultObjectIds!.Add(objId);
var result = await GetClient().PutObjectAsync(param, default); var result = await GetClient().PutClientCutObjectAsync(param, default);
var singleObjects = Mocker.PutSingleRequests.ToArray(); var singleObjects = Mocker.PutSingleRequests.ToArray();

View file

@ -50,7 +50,7 @@ public abstract class ObjectTestsBase
{ {
return FrostFSClient.GetTestInstance( return FrostFSClient.GetTestInstance(
Settings, Settings,
null, (url) => Grpc.Net.Client.GrpcChannel.ForAddress(new Uri(url)),
NetworkMocker.GetMock().Object, NetworkMocker.GetMock().Object,
SessionMocker.GetMock().Object, SessionMocker.GetMock().Object,
ContainerMocker.GetMock().Object, ContainerMocker.GetMock().Object,

View file

@ -39,7 +39,7 @@ public abstract class SessionTestsBase
{ {
return Client.FrostFSClient.GetTestInstance( return Client.FrostFSClient.GetTestInstance(
Settings, Settings,
null, (url) => Grpc.Net.Client.GrpcChannel.ForAddress(new Uri(url)),
new NetworkMocker(key).GetMock().Object, new NetworkMocker(key).GetMock().Object,
Mocker.GetMock().Object, Mocker.GetMock().Object,
new ContainerMocker(key).GetMock().Object, new ContainerMocker(key).GetMock().Object,