[#31] Client: fix for session #43
10 changed files with 247 additions and 146 deletions
|
@ -12,7 +12,7 @@ public class ClientKey(ECDsa key)
|
||||||
|
|
||||||
internal ByteString PublicKeyProto { get; } = ByteString.CopyFrom(key.PublicKey());
|
internal ByteString PublicKeyProto { get; } = ByteString.CopyFrom(key.PublicKey());
|
||||||
|
|
||||||
internal string PublicKey { get; } = key.PublicKey().ToString();
|
internal string PublicKey { get; } = Base58.Encode(key.PublicKey());
|
||||||
|
|
||||||
internal FrostFsOwner Owner { get; } = new FrostFsOwner(key.PublicKey().PublicKeyToAddress());
|
internal FrostFsOwner Owner { get; } = new FrostFsOwner(key.PublicKey().PublicKeyToAddress());
|
||||||
}
|
}
|
||||||
|
|
|
@ -447,7 +447,7 @@ public class FrostFSClient : IFrostFSClient
|
||||||
{
|
{
|
||||||
var invoker = CreateInvoker();
|
var invoker = CreateInvoker();
|
||||||
|
|
||||||
ObjectServiceClient = ObjectServiceClient ?? (
|
ObjectServiceClient ??= (
|
||||||
invoker != null
|
invoker != null
|
||||||
? new ObjectServiceClient(invoker)
|
? new ObjectServiceClient(invoker)
|
||||||
: new ObjectServiceClient(ClientCtx.Channel));
|
: new ObjectServiceClient(ClientCtx.Channel));
|
||||||
|
|
|
@ -47,7 +47,8 @@ public struct FrostFsPlacementPolicy(bool unique,
|
||||||
Filters = { },
|
Filters = { },
|
||||||
Selectors = { },
|
Selectors = { },
|
||||||
Replicas = { },
|
Replicas = { },
|
||||||
Unique = Unique
|
Unique = Unique,
|
||||||
|
ContainerBackupFactor = BackupFactor
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var replica in Replicas)
|
foreach (var replica in Replicas)
|
||||||
|
|
|
@ -45,9 +45,10 @@ public class FrostFsObject
|
||||||
/// <value>Reader for received data</value>
|
/// <value>Reader for received data</value>
|
||||||
public IObjectReader? ObjectReader { get; set; }
|
public IObjectReader? ObjectReader { get; set; }
|
||||||
|
|
||||||
internal byte[] SingleObjectPayload
|
public byte[] SingleObjectPayload
|
||||||
{
|
{
|
||||||
get { return bytes ?? []; }
|
get { return bytes ?? []; }
|
||||||
|
set { bytes = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
using FrostFS.Refs;
|
using FrostFS.Refs;
|
||||||
|
|
||||||
using FrostFS.SDK.Client;
|
using FrostFS.SDK.Client;
|
||||||
|
@ -36,7 +36,9 @@ public class FrostFsSessionToken
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (_id == Guid.Empty)
|
if (_id == Guid.Empty)
|
||||||
|
{
|
||||||
_id = ProtoId.ToUuid();
|
_id = ProtoId.ToUuid();
|
||||||
|
}
|
||||||
|
|
||||||
return _id;
|
return _id;
|
||||||
}
|
}
|
||||||
|
@ -47,7 +49,9 @@ public class FrostFsSessionToken
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (_sessionKey.IsEmpty)
|
if (_sessionKey.IsEmpty)
|
||||||
|
{
|
||||||
_sessionKey = ProtoSessionKey.Memory;
|
_sessionKey = ProtoSessionKey.Memory;
|
||||||
|
}
|
||||||
|
|
||||||
return _sessionKey;
|
return _sessionKey;
|
||||||
}
|
}
|
||||||
|
@ -69,12 +73,15 @@ public class FrostFsSessionToken
|
||||||
sessionToken.Body.Container = new() { Verb = verb };
|
sessionToken.Body.Container = new() { Verb = verb };
|
||||||
|
|
||||||
if (containerId != null)
|
if (containerId != null)
|
||||||
|
{
|
||||||
sessionToken.Body.Container.ContainerId = containerId;
|
sessionToken.Body.Container.ContainerId = containerId;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
sessionToken.Body.Container.Wildcard = true;
|
sessionToken.Body.Container.Wildcard = true;
|
||||||
|
}
|
||||||
|
|
||||||
sessionToken.Body.SessionKey = key.PublicKeyProto;
|
sessionToken.Body.SessionKey = key.PublicKeyProto;
|
||||||
|
|
||||||
sessionToken.Signature = key.ECDsaKey.SignMessagePart(sessionToken.Body);
|
sessionToken.Signature = key.ECDsaKey.SignMessagePart(sessionToken.Body);
|
||||||
|
|
||||||
return sessionToken;
|
return sessionToken;
|
||||||
|
@ -100,7 +107,9 @@ public class FrostFsSessionToken
|
||||||
ObjectSessionContext.Types.Target target = new() { Container = address.ContainerId };
|
ObjectSessionContext.Types.Target target = new() { Container = address.ContainerId };
|
||||||
|
|
||||||
if (address.ObjectId != null)
|
if (address.ObjectId != null)
|
||||||
|
{
|
||||||
target.Objects.Add(address.ObjectId);
|
target.Objects.Add(address.ObjectId);
|
||||||
|
}
|
||||||
|
|
||||||
sessionToken.Body.Object = new()
|
sessionToken.Body.Object = new()
|
||||||
{
|
{
|
||||||
|
@ -108,8 +117,6 @@ public class FrostFsSessionToken
|
||||||
Verb = verb
|
Verb = verb
|
||||||
};
|
};
|
||||||
|
|
||||||
sessionToken.Body.SessionKey = key.PublicKeyProto;
|
|
||||||
|
|
||||||
sessionToken.Signature = key.ECDsaKey.SignMessagePart(sessionToken.Body);
|
sessionToken.Signature = key.ECDsaKey.SignMessagePart(sessionToken.Body);
|
||||||
|
|
||||||
return sessionToken;
|
return sessionToken;
|
||||||
|
|
|
@ -32,6 +32,8 @@ namespace FrostFS.SDK.Client
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
chunkRequest.AddMetaHeader(args.XHeaders);
|
||||||
|
|
||||||
chunkRequest.Sign(this.ctx.Key.ECDsaKey);
|
chunkRequest.Sign(this.ctx.Key.ECDsaKey);
|
||||||
|
|
||||||
await streamer.Write(chunkRequest).ConfigureAwait(false);
|
await streamer.Write(chunkRequest).ConfigureAwait(false);
|
||||||
|
|
|
@ -10,7 +10,6 @@ using FrostFS.Refs;
|
||||||
using FrostFS.SDK.Client;
|
using FrostFS.SDK.Client;
|
||||||
using FrostFS.SDK.Client.Interfaces;
|
using FrostFS.SDK.Client.Interfaces;
|
||||||
using FrostFS.SDK.Client.Mappers.GRPC;
|
using FrostFS.SDK.Client.Mappers.GRPC;
|
||||||
using FrostFS.SDK.Cryptography;
|
|
||||||
using FrostFS.Session;
|
using FrostFS.Session;
|
||||||
|
|
||||||
using Google.Protobuf;
|
using Google.Protobuf;
|
||||||
|
@ -278,7 +277,7 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
|
||||||
var sessionToken = args.SessionToken ?? await GetDefaultSession(args, ctx).ConfigureAwait(false);
|
var sessionToken = args.SessionToken ?? await GetDefaultSession(args, ctx).ConfigureAwait(false);
|
||||||
|
|
||||||
var protoToken = sessionToken.CreateObjectTokenContext(
|
var protoToken = sessionToken.CreateObjectTokenContext(
|
||||||
new Address { ContainerId = grpcObject.Header.ContainerId, ObjectId = grpcObject.ObjectId },
|
new Address { ContainerId = grpcObject.Header.ContainerId },
|
||||||
ObjectSessionContext.Types.Verb.Put,
|
ObjectSessionContext.Types.Verb.Put,
|
||||||
ClientContext.Key);
|
ClientContext.Key);
|
||||||
|
|
||||||
|
@ -297,7 +296,7 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
|
||||||
{
|
{
|
||||||
var chunkSize = args.MaxChunkLength;
|
var chunkSize = args.MaxChunkLength;
|
||||||
Stream payload = args.Payload ?? throw new ArgumentNullException(nameof(args), "Stream parameter is null");
|
Stream payload = args.Payload ?? throw new ArgumentNullException(nameof(args), "Stream parameter is null");
|
||||||
|
|
||||||
var call = client.Patch(null, ctx.GetDeadline(), ctx.CancellationToken);
|
var call = client.Patch(null, ctx.GetDeadline(), ctx.CancellationToken);
|
||||||
|
|
||||||
byte[]? chunkBuffer = null;
|
byte[]? chunkBuffer = null;
|
||||||
|
@ -306,31 +305,15 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
|
||||||
// common
|
// common
|
||||||
chunkBuffer = ArrayPool<byte>.Shared.Rent(chunkSize);
|
chunkBuffer = ArrayPool<byte>.Shared.Rent(chunkSize);
|
||||||
|
|
||||||
|
bool isFirstChunk = true;
|
||||||
|
ulong currentPos = args.Range.Offset;
|
||||||
|
|
||||||
var address = new Address
|
var address = new Address
|
||||||
{
|
{
|
||||||
ObjectId = args.Address.ObjectId,
|
ObjectId = args.Address.ObjectId,
|
||||||
ContainerId = args.Address.ContainerId
|
ContainerId = args.Address.ContainerId
|
||||||
};
|
};
|
||||||
|
|
||||||
var sessionToken = args.SessionToken ?? await GetDefaultSession(args, ctx).ConfigureAwait(false);
|
|
||||||
|
|
||||||
var protoToken = sessionToken.CreateObjectTokenContext(
|
|
||||||
address,
|
|
||||||
ObjectSessionContext.Types.Verb.Patch,
|
|
||||||
ClientContext.Key);
|
|
||||||
|
|
||||||
var request = new PatchRequest()
|
|
||||||
{
|
|
||||||
Body = new()
|
|
||||||
{
|
|
||||||
Address = address,
|
|
||||||
ReplaceAttributes = args.ReplaceAttributes,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
bool isFirstChunk = true;
|
|
||||||
ulong currentPos = args.Range.Offset;
|
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
var bytesCount = await payload.ReadAsync(chunkBuffer, 0, chunkSize, ctx.CancellationToken).ConfigureAwait(false);
|
var bytesCount = await payload.ReadAsync(chunkBuffer, 0, chunkSize, ctx.CancellationToken).ConfigureAwait(false);
|
||||||
|
@ -340,41 +323,62 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isFirstChunk && args.NewAttributes != null && args.NewAttributes.Length > 0)
|
var request = new PatchRequest()
|
||||||
{
|
{
|
||||||
foreach (var attr in args.NewAttributes)
|
Body = new()
|
||||||
{
|
{
|
||||||
request.Body.NewAttributes.Add(attr.ToMessage());
|
Address = address,
|
||||||
|
Patch = new PatchRequest.Types.Body.Types.Patch
|
||||||
|
{
|
||||||
|
Chunk = ByteString.CopyFrom(chunkBuffer, 0, bytesCount),
|
||||||
|
SourceRange = new Object.Range { Offset = currentPos, Length = (ulong)bytesCount }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
request.Body.Patch = new PatchRequest.Types.Body.Types.Patch
|
|
||||||
{
|
|
||||||
Chunk = ByteString.CopyFrom(chunkBuffer, 0, bytesCount),
|
|
||||||
SourceRange = new Object.Range { Offset = currentPos, Length = (ulong)bytesCount }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
currentPos += (ulong)bytesCount;
|
if (isFirstChunk)
|
||||||
|
{
|
||||||
|
var sessionToken = args.SessionToken ?? await GetDefaultSession(args, ctx).ConfigureAwait(false);
|
||||||
|
|
||||||
request.AddMetaHeader(args.XHeaders, protoToken);
|
var protoToken = sessionToken.CreateObjectTokenContext(
|
||||||
|
address,
|
||||||
|
ObjectSessionContext.Types.Verb.Patch,
|
||||||
|
ClientContext.Key);
|
||||||
|
|
||||||
|
request.AddMetaHeader(args.XHeaders, protoToken);
|
||||||
|
|
||||||
|
if (args.NewAttributes != null && args.NewAttributes.Length > 0)
|
||||||
|
{
|
||||||
|
foreach (var attr in args.NewAttributes)
|
||||||
|
{
|
||||||
|
request.Body.NewAttributes.Add(attr.ToMessage());
|
||||||
|
request.Body.ReplaceAttributes = args.ReplaceAttributes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isFirstChunk = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
request.AddMetaHeader(args.XHeaders);
|
||||||
|
}
|
||||||
|
|
||||||
request.Sign(ClientContext.Key.ECDsaKey);
|
request.Sign(ClientContext.Key.ECDsaKey);
|
||||||
|
|
||||||
await call.RequestStream.WriteAsync(request).ConfigureAwait(false);
|
await call.RequestStream.WriteAsync(request).ConfigureAwait(false);
|
||||||
|
|
||||||
isFirstChunk = false;
|
currentPos += (ulong)bytesCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
await call.RequestStream.CompleteAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (chunkBuffer != null)
|
if (chunkBuffer != null)
|
||||||
{
|
{
|
||||||
ArrayPool<byte>.Shared.Return(chunkBuffer);
|
ArrayPool<byte>.Shared.Return(chunkBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await call.RequestStream.CompleteAsync().ConfigureAwait(false);
|
||||||
var response = await call.ResponseAsync.ConfigureAwait(false);
|
var response = await call.ResponseAsync.ConfigureAwait(false);
|
||||||
|
|
||||||
Verifier.CheckResponse(response);
|
Verifier.CheckResponse(response);
|
||||||
|
@ -513,7 +517,7 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
|
||||||
{
|
{
|
||||||
// send chunks limited to default or user's settings
|
// send chunks limited to default or user's settings
|
||||||
var bufferSize = objectLimitSize > 0 ?
|
var bufferSize = objectLimitSize > 0 ?
|
||||||
(int)Math.Min(objectLimitSize - sentBytes, chunkSize)
|
Math.Min(objectLimitSize - sentBytes, chunkSize)
|
||||||
: chunkSize;
|
: chunkSize;
|
||||||
|
|
||||||
var bytesCount = await payload.ReadAsync(chunkBuffer, 0, bufferSize, ctx.CancellationToken).ConfigureAwait(false);
|
var bytesCount = await payload.ReadAsync(chunkBuffer, 0, bufferSize, ctx.CancellationToken).ConfigureAwait(false);
|
||||||
|
@ -531,6 +535,8 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
chunkRequest.AddMetaHeader(args.XHeaders);
|
||||||
|
|
||||||
chunkRequest.Sign(ClientContext.Key.ECDsaKey);
|
chunkRequest.Sign(ClientContext.Key.ECDsaKey);
|
||||||
|
|
||||||
await stream.Write(chunkRequest).ConfigureAwait(false);
|
await stream.Write(chunkRequest).ConfigureAwait(false);
|
||||||
|
@ -571,8 +577,6 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
|
||||||
ObjectTools.SetSplitValues(grpcHeader, header.Split, ClientContext.Owner, ClientContext.Version, ClientContext.Key);
|
ObjectTools.SetSplitValues(grpcHeader, header.Split, ClientContext.Owner, ClientContext.Version, ClientContext.Key);
|
||||||
}
|
}
|
||||||
|
|
||||||
var oid = new ObjectID { Value = grpcHeader.Sha256() };
|
|
||||||
|
|
||||||
var initRequest = new PutRequest
|
var initRequest = new PutRequest
|
||||||
{
|
{
|
||||||
Body = new PutRequest.Types.Body
|
Body = new PutRequest.Types.Body
|
||||||
|
@ -587,7 +591,7 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
|
||||||
var sessionToken = args.SessionToken ?? await GetDefaultSession(args, ctx).ConfigureAwait(false);
|
var sessionToken = args.SessionToken ?? await GetDefaultSession(args, ctx).ConfigureAwait(false);
|
||||||
|
|
||||||
var protoToken = sessionToken.CreateObjectTokenContext(
|
var protoToken = sessionToken.CreateObjectTokenContext(
|
||||||
new Address { ContainerId = grpcHeader.ContainerId, ObjectId = oid },
|
new Address { ContainerId = grpcHeader.ContainerId },
|
||||||
ObjectSessionContext.Types.Verb.Put,
|
ObjectSessionContext.Types.Verb.Put,
|
||||||
ClientContext.Key);
|
ClientContext.Key);
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,10 @@ public static class RequestConstructor
|
||||||
if (request.MetaHeader is not null)
|
if (request.MetaHeader is not null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
request.MetaHeader = MetaHeader.Default().ToMessage();
|
var metaHeader = MetaHeader.Default();
|
||||||
|
metaHeader.Ttl = 2;
|
||||||
|
|
||||||
|
request.MetaHeader = metaHeader.ToMessage();
|
||||||
|
|
||||||
if (sessionToken != null)
|
if (sessionToken != null)
|
||||||
request.MetaHeader.SessionToken = sessionToken;
|
request.MetaHeader.SessionToken = sessionToken;
|
||||||
|
|
|
@ -7,6 +7,7 @@ using FrostFS.SDK.Client;
|
||||||
using FrostFS.SDK.Client.Interfaces;
|
using FrostFS.SDK.Client.Interfaces;
|
||||||
using FrostFS.SDK.Cryptography;
|
using FrostFS.SDK.Cryptography;
|
||||||
using FrostFS.SDK.SmokeTests;
|
using FrostFS.SDK.SmokeTests;
|
||||||
|
using FrostFS.Session;
|
||||||
using Google.Protobuf;
|
using Google.Protobuf;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
|
@ -21,6 +22,8 @@ public class SmokeClientTests : SmokeTestsBase
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void AccountTest()
|
public async void AccountTest()
|
||||||
{
|
{
|
||||||
|
var test = lightWait.Timeout;
|
||||||
|
|
||||||
var client = FrostFSClient.GetInstance(ClientOptions, GrpcChannel);
|
var client = FrostFSClient.GetInstance(ClientOptions, GrpcChannel);
|
||||||
|
|
||||||
var result = await client.GetBalanceAsync(default);
|
var result = await client.GetBalanceAsync(default);
|
||||||
|
@ -66,8 +69,6 @@ public class SmokeClientTests : SmokeTestsBase
|
||||||
|
|
||||||
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);
|
||||||
|
@ -84,7 +85,7 @@ public class SmokeClientTests : SmokeTestsBase
|
||||||
|
|
||||||
var createContainerParam = new PrmContainerCreate(
|
var createContainerParam = new PrmContainerCreate(
|
||||||
new FrostFsContainerInfo(
|
new FrostFsContainerInfo(
|
||||||
new FrostFsPlacementPolicy(true, 1, [], [], new FrostFsReplica(1)),
|
new FrostFsPlacementPolicy(true, 1, [], [], new FrostFsReplica(3)),
|
||||||
[new FrostFsAttributePair("__SYSTEM__DISABLE_HOMOMORPHIC_HASHING", "true")]),
|
[new FrostFsAttributePair("__SYSTEM__DISABLE_HOMOMORPHIC_HASHING", "true")]),
|
||||||
PrmWait.DefaultParams,
|
PrmWait.DefaultParams,
|
||||||
xheaders: ["key1", "value1"]);
|
xheaders: ["key1", "value1"]);
|
||||||
|
@ -133,7 +134,7 @@ public class SmokeClientTests : SmokeTestsBase
|
||||||
|
|
||||||
var createContainerParam = new PrmContainerCreate(
|
var createContainerParam = new PrmContainerCreate(
|
||||||
new FrostFsContainerInfo(
|
new FrostFsContainerInfo(
|
||||||
new FrostFsPlacementPolicy(true, 1, [], [], new FrostFsReplica(1)),
|
new FrostFsPlacementPolicy(true, 1, [], [], new FrostFsReplica(3)),
|
||||||
[new FrostFsAttributePair("__SYSTEM__DISABLE_HOMOMORPHIC_HASHING", "true")]),
|
[new FrostFsAttributePair("__SYSTEM__DISABLE_HOMOMORPHIC_HASHING", "true")]),
|
||||||
lightWait);
|
lightWait);
|
||||||
|
|
||||||
|
@ -221,7 +222,7 @@ public class SmokeClientTests : SmokeTestsBase
|
||||||
|
|
||||||
var createContainerParam = new PrmContainerCreate(
|
var createContainerParam = new PrmContainerCreate(
|
||||||
new FrostFsContainerInfo(
|
new FrostFsContainerInfo(
|
||||||
new FrostFsPlacementPolicy(true, 1, [], [], new FrostFsReplica(1)),
|
new FrostFsPlacementPolicy(true, 1, [], [], new FrostFsReplica(3)),
|
||||||
[new FrostFsAttributePair("__SYSTEM__DISABLE_HOMOMORPHIC_HASHING", "true")]),
|
[new FrostFsAttributePair("__SYSTEM__DISABLE_HOMOMORPHIC_HASHING", "true")]),
|
||||||
PrmWait.DefaultParams,
|
PrmWait.DefaultParams,
|
||||||
xheaders: ["testKey", "testValue"]);
|
xheaders: ["testKey", "testValue"]);
|
||||||
|
@ -285,6 +286,81 @@ public class SmokeClientTests : SmokeTestsBase
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert.Equal(SHA256.HashData(bytes), SHA256.HashData(downloadedBytes));
|
Assert.Equal(SHA256.HashData(bytes), SHA256.HashData(downloadedBytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(1)]
|
||||||
|
[InlineData(500 * 1024)]
|
||||||
|
[InlineData(3 * 1024 * 1024)]
|
||||||
|
public async void PutSingleObjectTest(int objectSize)
|
||||||
|
{
|
||||||
|
var options = ClientOptions;
|
||||||
|
|
||||||
|
var client = FrostFSClient.GetInstance(options, GrpcChannel);
|
||||||
|
|
||||||
|
await Cleanup(client);
|
||||||
|
|
||||||
|
var ctx = new CallContext();
|
||||||
|
|
||||||
|
var createContainerParam = new PrmContainerCreate(
|
||||||
|
new FrostFsContainerInfo(
|
||||||
|
new FrostFsPlacementPolicy(true, 1, [], [], new FrostFsReplica(3)),
|
||||||
|
[new FrostFsAttributePair("__SYSTEM__DISABLE_HOMOMORPHIC_HASHING", "true")]),
|
||||||
|
PrmWait.DefaultParams,
|
||||||
|
xheaders: ["testKey1", "testValue1"]);
|
||||||
|
|
||||||
|
var containerId = await client.CreateContainerAsync(createContainerParam, ctx);
|
||||||
|
|
||||||
|
var container = await client.GetContainerAsync(new PrmContainerGet(containerId), default);
|
||||||
|
Assert.NotNull(container);
|
||||||
|
|
||||||
|
await AddObjectRules(client, containerId);
|
||||||
|
|
||||||
|
var bytes = GetRandomBytes(objectSize);
|
||||||
|
|
||||||
|
var header = new FrostFsObjectHeader(
|
||||||
|
containerId: containerId,
|
||||||
|
type: FrostFsObjectType.Regular,
|
||||||
|
[new FrostFsAttributePair("fileName1", "test1")]);
|
||||||
|
|
||||||
|
var obj = new FrostFsObject(header) { SingleObjectPayload = bytes };
|
||||||
|
|
||||||
|
var param = new PrmSingleObjectPut(obj);
|
||||||
|
|
||||||
|
var objectId = await client.PutSingleObjectAsync(param, default).ConfigureAwait(true);
|
||||||
|
|
||||||
|
var filter = new FilterByAttributePair(FrostFsMatchType.Equals, "fileName1", "test1");
|
||||||
|
|
||||||
|
bool hasObject = false;
|
||||||
|
await foreach (var objId in client.SearchObjectsAsync(new PrmObjectSearch(containerId, null, [], filter), default))
|
||||||
|
{
|
||||||
|
hasObject = true;
|
||||||
|
|
||||||
|
var res = await client.GetObjectHeadAsync(new PrmObjectHeadGet(containerId, objectId), default);
|
||||||
|
|
||||||
|
var objHeader = res.HeaderInfo;
|
||||||
|
Assert.NotNull(objHeader);
|
||||||
|
Assert.Equal((ulong)bytes.Length, objHeader.PayloadLength);
|
||||||
|
Assert.NotNull(objHeader.Attributes);
|
||||||
|
Assert.Single(objHeader.Attributes);
|
||||||
|
Assert.Equal("fileName1", objHeader.Attributes.First().Key);
|
||||||
|
Assert.Equal("test1", objHeader.Attributes.First().Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.True(hasObject);
|
||||||
|
|
||||||
|
var @object = await client.GetObjectAsync(new PrmObjectGet(containerId, objectId), default);
|
||||||
|
|
||||||
|
var downloadedBytes = new byte[@object.Header.PayloadLength];
|
||||||
|
MemoryStream ms = new(downloadedBytes);
|
||||||
|
|
||||||
|
ReadOnlyMemory<byte>? chunk = null;
|
||||||
|
while ((chunk = await @object.ObjectReader!.ReadChunk()) != null)
|
||||||
|
{
|
||||||
|
ms.Write(chunk.Value.Span);
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.Equal(SHA256.HashData(bytes), SHA256.HashData(downloadedBytes));
|
||||||
|
|
||||||
await Cleanup(client);
|
await Cleanup(client);
|
||||||
|
|
||||||
|
@ -294,6 +370,14 @@ public class SmokeClientTests : SmokeTestsBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async void CleanupTest()
|
||||||
|
{
|
||||||
|
var client = FrostFSClient.GetInstance(ClientOptions, GrpcChannel);
|
||||||
|
|
||||||
|
await Cleanup(client);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void PatchTest()
|
public async void PatchTest()
|
||||||
{
|
{
|
||||||
|
@ -387,7 +471,7 @@ public class SmokeClientTests : SmokeTestsBase
|
||||||
|
|
||||||
var createContainerParam = new PrmContainerCreate(
|
var createContainerParam = new PrmContainerCreate(
|
||||||
new FrostFsContainerInfo(
|
new FrostFsContainerInfo(
|
||||||
new FrostFsPlacementPolicy(true, 1, [], [], new FrostFsReplica(1)),
|
new FrostFsPlacementPolicy(true, 1, [], [], new FrostFsReplica(3)),
|
||||||
[new FrostFsAttributePair("__SYSTEM__DISABLE_HOMOMORPHIC_HASHING", "true")]),
|
[new FrostFsAttributePair("__SYSTEM__DISABLE_HOMOMORPHIC_HASHING", "true")]),
|
||||||
PrmWait.DefaultParams,
|
PrmWait.DefaultParams,
|
||||||
xheaders: ["testKey", "testValue"]);
|
xheaders: ["testKey", "testValue"]);
|
||||||
|
@ -429,13 +513,6 @@ public class SmokeClientTests : SmokeTestsBase
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert.Equal(SHA256.HashData(bytes.AsSpan().Slice(50, 100)), SHA256.HashData(downloadedBytes));
|
Assert.Equal(SHA256.HashData(bytes.AsSpan().Slice(50, 100)), SHA256.HashData(downloadedBytes));
|
||||||
|
|
||||||
await Cleanup(client);
|
|
||||||
|
|
||||||
await foreach (var _ in client.ListContainersAsync(default, default))
|
|
||||||
{
|
|
||||||
Assert.Fail("Containers exist");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -447,7 +524,7 @@ public class SmokeClientTests : SmokeTestsBase
|
||||||
|
|
||||||
var createContainerParam = new PrmContainerCreate(
|
var createContainerParam = new PrmContainerCreate(
|
||||||
new FrostFsContainerInfo(
|
new FrostFsContainerInfo(
|
||||||
new FrostFsPlacementPolicy(true, 1, [], [], new FrostFsReplica(1)),
|
new FrostFsPlacementPolicy(true, 1, [], [], new FrostFsReplica(3)),
|
||||||
[new FrostFsAttributePair("__SYSTEM__DISABLE_HOMOMORPHIC_HASHING", "true")]),
|
[new FrostFsAttributePair("__SYSTEM__DISABLE_HOMOMORPHIC_HASHING", "true")]),
|
||||||
PrmWait.DefaultParams,
|
PrmWait.DefaultParams,
|
||||||
xheaders: ["testKey", "testValue"]);
|
xheaders: ["testKey", "testValue"]);
|
||||||
|
@ -482,13 +559,8 @@ public class SmokeClientTests : SmokeTestsBase
|
||||||
foreach (var hash in hashes)
|
foreach (var hash in hashes)
|
||||||
{
|
{
|
||||||
var x = hash[..32].ToArray();
|
var x = hash[..32].ToArray();
|
||||||
}
|
Assert.NotNull(x);
|
||||||
|
Assert.True(x.Length > 0);
|
||||||
await Cleanup(client);
|
|
||||||
|
|
||||||
await foreach (var _ in client.ListContainersAsync(default, default))
|
|
||||||
{
|
|
||||||
Assert.Fail("Containers exist");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -499,7 +571,7 @@ public class SmokeClientTests : SmokeTestsBase
|
||||||
public async void SimpleScenarioWithSessionTest(int objectSize)
|
public async void SimpleScenarioWithSessionTest(int objectSize)
|
||||||
{
|
{
|
||||||
var client = FrostFSClient.GetInstance(ClientOptions, GrpcChannel);
|
var client = FrostFSClient.GetInstance(ClientOptions, GrpcChannel);
|
||||||
//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);
|
||||||
|
|
||||||
await Cleanup(client);
|
await Cleanup(client);
|
||||||
|
@ -508,7 +580,7 @@ public class SmokeClientTests : SmokeTestsBase
|
||||||
|
|
||||||
var createContainerParam = new PrmContainerCreate(
|
var createContainerParam = new PrmContainerCreate(
|
||||||
new FrostFsContainerInfo(
|
new FrostFsContainerInfo(
|
||||||
new FrostFsPlacementPolicy(true, 1, [], [], new FrostFsReplica(1)),
|
new FrostFsPlacementPolicy(true, 1, [], [], new FrostFsReplica(3)),
|
||||||
[new FrostFsAttributePair("__SYSTEM__DISABLE_HOMOMORPHIC_HASHING", "true")]),
|
[new FrostFsAttributePair("__SYSTEM__DISABLE_HOMOMORPHIC_HASHING", "true")]),
|
||||||
PrmWait.DefaultParams);
|
PrmWait.DefaultParams);
|
||||||
|
|
||||||
|
@ -574,14 +646,8 @@ public class SmokeClientTests : SmokeTestsBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Fact]
|
||||||
[InlineData(1)]
|
public async void ClientCutScenarioTest()
|
||||||
[InlineData(64 * 1024 * 1024)] // exactly 1 block size - 64MB
|
|
||||||
[InlineData(64 * 1024 * 1024 - 1)]
|
|
||||||
[InlineData(64 * 1024 * 1024 + 1)]
|
|
||||||
[InlineData(2 * 64 * 1024 * 1024 + 256)]
|
|
||||||
[InlineData(200)]
|
|
||||||
public async void ClientCutScenarioTest(int objectSize)
|
|
||||||
{
|
{
|
||||||
var options = ClientOptions;
|
var options = ClientOptions;
|
||||||
options.Value.Interceptors.Add(new CallbackInterceptor());
|
options.Value.Interceptors.Add(new CallbackInterceptor());
|
||||||
|
@ -590,71 +656,57 @@ public class SmokeClientTests : SmokeTestsBase
|
||||||
|
|
||||||
await Cleanup(client);
|
await Cleanup(client);
|
||||||
|
|
||||||
var createContainerParam = new PrmContainerCreate(
|
int[] replicas = [3]; //1
|
||||||
new FrostFsContainerInfo(
|
|
||||||
new FrostFsPlacementPolicy(true, 1, [], [], new FrostFsReplica(1)),
|
|
||||||
[new FrostFsAttributePair("__SYSTEM__DISABLE_HOMOMORPHIC_HASHING", "true")]),
|
|
||||||
lightWait);
|
|
||||||
|
|
||||||
var containerId = await client.CreateContainerAsync(createContainerParam, default);
|
foreach (var rep in replicas)
|
||||||
|
|
||||||
var ctx = new CallContext(TimeSpan.FromSeconds(10));
|
|
||||||
|
|
||||||
var container = await client.GetContainerAsync(new PrmContainerGet(containerId), ctx);
|
|
||||||
|
|
||||||
Assert.NotNull(container);
|
|
||||||
|
|
||||||
await AddObjectRules(client, containerId);
|
|
||||||
|
|
||||||
byte[] bytes = GetRandomBytes(objectSize);
|
|
||||||
|
|
||||||
var param = new PrmObjectClientCutPut(
|
|
||||||
new FrostFsObjectHeader(
|
|
||||||
containerId: containerId,
|
|
||||||
type: FrostFsObjectType.Regular,
|
|
||||||
[new FrostFsAttributePair("fileName", "test")]),
|
|
||||||
payload: new MemoryStream(bytes));
|
|
||||||
|
|
||||||
var objectId = await client.PutClientCutObjectAsync(param, default).ConfigureAwait(true);
|
|
||||||
|
|
||||||
var filter1 = new FilterByOwnerId(FrostFsMatchType.Equals, OwnerId!);
|
|
||||||
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 createContainerParam = new PrmContainerCreate(
|
||||||
}
|
new FrostFsContainerInfo(
|
||||||
|
new FrostFsPlacementPolicy(true, 1, [], [], new FrostFsReplica(rep)),
|
||||||
|
[new FrostFsAttributePair("__SYSTEM__DISABLE_HOMOMORPHIC_HASHING", "true")]),
|
||||||
|
lightWait);
|
||||||
|
|
||||||
var @object = await client.GetObjectAsync(new PrmObjectGet(containerId, objectId), default);
|
var containerId = await client.CreateContainerAsync(createContainerParam, default);
|
||||||
|
|
||||||
var downloadedBytes = new byte[@object.Header.PayloadLength];
|
var ctx = new CallContext(TimeSpan.FromSeconds(10));
|
||||||
MemoryStream ms = new(downloadedBytes);
|
|
||||||
|
|
||||||
ReadOnlyMemory<byte>? chunk = null;
|
var container = await client.GetContainerAsync(new PrmContainerGet(containerId), ctx);
|
||||||
while ((chunk = await @object.ObjectReader!.ReadChunk()) != null)
|
|
||||||
{
|
|
||||||
ms.Write(chunk.Value.Span);
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.Equal(SHA256.HashData(bytes), SHA256.HashData(downloadedBytes));
|
Assert.NotNull(container);
|
||||||
|
|
||||||
await CheckFilter(client, containerId, new FilterByRootObject());
|
await AddObjectRules(client, containerId);
|
||||||
|
|
||||||
|
var mb = 1024 * 1024;
|
||||||
|
|
||||||
await Cleanup(client);
|
int[] objectSizes = [1, 1024, 64 * mb + 1]; //64 * mb, 64 * mb - 1, , 2 * 64 * mb + 256];
|
||||||
|
|
||||||
var deadline = DateTime.UtcNow.Add(TimeSpan.FromSeconds(5));
|
foreach (var objectSize in objectSizes)
|
||||||
|
|
||||||
IAsyncEnumerator<FrostFsContainerId>? enumerator = null;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (deadline <= DateTime.UtcNow)
|
|
||||||
{
|
{
|
||||||
Assert.Fail("Containers exist");
|
byte[] bytes = GetRandomBytes(objectSize);
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
enumerator = client.ListContainersAsync(default, default).GetAsyncEnumerator();
|
var param = new PrmObjectClientCutPut(
|
||||||
await Task.Delay(500);
|
new FrostFsObjectHeader(
|
||||||
|
containerId: containerId,
|
||||||
|
type: FrostFsObjectType.Regular,
|
||||||
|
[new FrostFsAttributePair("fileName", "test")]),
|
||||||
|
payload: new MemoryStream(bytes));
|
||||||
|
|
||||||
|
var objectId = await client.PutClientCutObjectAsync(param, default).ConfigureAwait(true);
|
||||||
|
|
||||||
|
var @object = await client.GetObjectAsync(new PrmObjectGet(containerId, objectId), default);
|
||||||
|
|
||||||
|
var downloadedBytes = new byte[@object.Header.PayloadLength];
|
||||||
|
MemoryStream ms = new(downloadedBytes);
|
||||||
|
|
||||||
|
ReadOnlyMemory<byte>? chunk = null;
|
||||||
|
while ((chunk = await @object.ObjectReader!.ReadChunk()) != null)
|
||||||
|
{
|
||||||
|
ms.Write(chunk.Value.Span);
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.Equal(SHA256.HashData(bytes), SHA256.HashData(downloadedBytes));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
while (await enumerator!.MoveNextAsync());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -712,6 +764,43 @@ public class SmokeClientTests : SmokeTestsBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static async Task AddContainerRules(IFrostFSClient client, FrostFsContainerId containerId)
|
||||||
|
{
|
||||||
|
var addChainPrm = new PrmApeChainAdd(
|
||||||
|
new FrostFsChainTarget(FrostFsTargetType.Container, containerId.GetValue()),
|
||||||
|
new FrostFsChain
|
||||||
|
{
|
||||||
|
ID = Encoding.ASCII.GetBytes("chain-id-test1"),
|
||||||
|
Rules = [
|
||||||
|
new FrostFsRule
|
||||||
|
{
|
||||||
|
Status = RuleStatus.Allow,
|
||||||
|
Actions = new Actions(inverted: false, names: ["*"]),
|
||||||
|
Resources = new Resource (inverted: false, names: [$"native:container/*"]),
|
||||||
|
Any = false,
|
||||||
|
Conditions = []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
MatchType = RuleMatchType.DenyPriority
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
await client.AddChainAsync(addChainPrm, default);
|
||||||
|
|
||||||
|
var listChainPrm = new PrmApeChainList(new FrostFsChainTarget(FrostFsTargetType.Container, containerId.GetValue()));
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
await Task.Delay(1000);
|
||||||
|
var chains = await client.ListChainAsync(listChainPrm, default);
|
||||||
|
|
||||||
|
if (chains.Length > 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.Delay(8000);
|
||||||
|
}
|
||||||
|
|
||||||
private static async Task AddObjectRules(IFrostFSClient client, FrostFsContainerId containerId)
|
private static async Task AddObjectRules(IFrostFSClient client, FrostFsContainerId containerId)
|
||||||
{
|
{
|
||||||
var addChainPrm = new PrmApeChainAdd(
|
var addChainPrm = new PrmApeChainAdd(
|
||||||
|
@ -735,17 +824,6 @@ public class SmokeClientTests : SmokeTestsBase
|
||||||
|
|
||||||
await client.AddChainAsync(addChainPrm, default);
|
await client.AddChainAsync(addChainPrm, default);
|
||||||
|
|
||||||
var listChainPrm = new PrmApeChainList(new FrostFsChainTarget(FrostFsTargetType.Container, containerId.GetValue()));
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
await Task.Delay(1000);
|
|
||||||
var chains = await client.ListChainAsync(listChainPrm, default);
|
|
||||||
|
|
||||||
if (chains.Length > 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
await Task.Delay(8000);
|
await Task.Delay(8000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,14 @@ namespace FrostFS.SDK.Tests.Smoke;
|
||||||
|
|
||||||
public abstract class SmokeTestsBase
|
public abstract class SmokeTestsBase
|
||||||
{
|
{
|
||||||
|
// cluster Ori
|
||||||
|
internal readonly string url = "http://10.78.128.207:8080";
|
||||||
|
internal readonly string keyString = "L4JWLdedUd4b21sriRHtCPGkjG2Mryz2AWLiVqTBSNyxxyAUcc7s";
|
||||||
|
|
||||||
|
|
||||||
// cluster
|
// cluster
|
||||||
internal readonly string url = "http://10.78.128.190:8080";
|
// internal readonly string url = "http://10.78.128.190:8080";
|
||||||
internal readonly string keyString = "L47c3bunc6bJd7uEAfPUae2VkyupFR9nizoH6jfPonzQxijqH2Ba";
|
// internal readonly string keyString = "L47c3bunc6bJd7uEAfPUae2VkyupFR9nizoH6jfPonzQxijqH2Ba";
|
||||||
|
|
||||||
// WSL2
|
// WSL2
|
||||||
//internal readonly string url = "http://172.29.238.97:8080";
|
//internal readonly string url = "http://172.29.238.97:8080";
|
||||||
|
|
Loading…
Add table
Reference in a new issue