[#69] Fix for Patch and uint types
All checks were successful
DCO / DCO (pull_request) Successful in 23s
lint-build / dotnet8.0 (pull_request) Successful in 34s
lint-build / dotnet8.0 (push) Successful in 35s

Signed-off-by: Pavel Gross <p.gross@yadro.com>
This commit is contained in:
Pavel Gross 2025-04-30 15:19:20 +03:00
parent eebba7665b
commit 0816be732a
20 changed files with 212 additions and 153 deletions

View file

@ -8,7 +8,7 @@ using System.Runtime.CompilerServices;
"e15ab287e6239c98d5dfa91615bd77485d523a3a3f65a4e5028454cedd5ac4d9eca6da18b81985"+ "e15ab287e6239c98d5dfa91615bd77485d523a3a3f65a4e5028454cedd5ac4d9eca6da18b81985"+
"ac6905d33cc64b5a2587050c16f67b71ef8889dbd3c90ef7cc0b06bbbe09886601d195f5db179a"+ "ac6905d33cc64b5a2587050c16f67b71ef8889dbd3c90ef7cc0b06bbbe09886601d195f5db179a"+
"3c2a25b1")] "3c2a25b1")]
[assembly: AssemblyFileVersion("1.0.6.0")] [assembly: AssemblyFileVersion("1.0.7.0")]
[assembly: AssemblyProduct("FrostFS.SDK.Client")] [assembly: AssemblyProduct("FrostFS.SDK.Client")]
[assembly: AssemblyTitle("FrostFS.SDK.Client")] [assembly: AssemblyTitle("FrostFS.SDK.Client")]
[assembly: AssemblyVersion("1.0.6")] [assembly: AssemblyVersion("1.0.7")]

View file

@ -6,7 +6,7 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<AnalysisMode>AllEnabledByDefault</AnalysisMode> <AnalysisMode>AllEnabledByDefault</AnalysisMode>
<PackageId>FrostFS.SDK.Client</PackageId> <PackageId>FrostFS.SDK.Client</PackageId>
<Version>1.0.6</Version> <Version>1.0.7</Version>
<Description> <Description>
C# SDK for FrostFS gRPC native protocol C# SDK for FrostFS gRPC native protocol
</Description> </Description>

View file

@ -16,8 +16,8 @@ public static class MetaHeaderMapper
return new RequestMetaHeader return new RequestMetaHeader
{ {
Version = metaHeader.Version.ToMessage(), Version = metaHeader.Version.ToMessage(),
Epoch = (uint)metaHeader.Epoch, Epoch = metaHeader.Epoch,
Ttl = (uint)metaHeader.Ttl Ttl = metaHeader.Ttl
}; };
} }
} }

View file

@ -11,7 +11,7 @@ public static class PolicyMapper
{ {
return new Replica return new Replica
{ {
Count = (uint)replica.Count, Count = replica.Count,
Selector = replica.Selector, Selector = replica.Selector,
EcDataCount = replica.EcDataCount, EcDataCount = replica.EcDataCount,
EcParityCount = replica.EcParityCount EcParityCount = replica.EcParityCount
@ -25,7 +25,7 @@ public static class PolicyMapper
throw new ArgumentNullException(nameof(replica)); throw new ArgumentNullException(nameof(replica));
} }
return new FrostFsReplica((int)replica.Count, replica.Selector) return new FrostFsReplica(replica.Count, replica.Selector)
{ {
EcDataCount = replica.EcDataCount, EcDataCount = replica.EcDataCount,
EcParityCount = replica.EcParityCount EcParityCount = replica.EcParityCount

View file

@ -18,7 +18,7 @@ public static class VersionMapper
throw new System.ArgumentNullException(nameof(model)); throw new System.ArgumentNullException(nameof(model));
} }
var key = model.Major << 16 + model.Minor; var key = (int)model.Major << 16 + (int)model.Minor;
if (!_cacheMessages.ContainsKey(key)) if (!_cacheMessages.ContainsKey(key))
{ {
@ -28,8 +28,8 @@ public static class VersionMapper
_spinlock.Enter(ref lockTaken); _spinlock.Enter(ref lockTaken);
var message = new Version var message = new Version
{ {
Major = (uint)model.Major, Major = model.Major,
Minor = (uint)model.Minor Minor = model.Minor
}; };
_cacheMessages.Add(key, message); _cacheMessages.Add(key, message);
@ -64,7 +64,7 @@ public static class VersionMapper
try try
{ {
_spinlock.Enter(ref lockTaken); _spinlock.Enter(ref lockTaken);
var model = new FrostFsVersion((int)message.Major, (int)message.Minor); var model = new FrostFsVersion(message.Major, message.Minor);
_cacheModels.Add(key, model); _cacheModels.Add(key, model);
return model; return model;

View file

@ -4,12 +4,12 @@ namespace FrostFS.SDK;
public struct FrostFsReplica : IEquatable<FrostFsReplica> public struct FrostFsReplica : IEquatable<FrostFsReplica>
{ {
public int Count { get; set; } public uint Count { get; set; }
public string Selector { get; set; } public string Selector { get; set; }
public uint EcDataCount { get; set; } public uint EcDataCount { get; set; }
public uint EcParityCount { get; set; } public uint EcParityCount { get; set; }
public FrostFsReplica(int count, string? selector = null) public FrostFsReplica(uint count, string? selector = null)
{ {
selector ??= string.Empty; selector ??= string.Empty;
@ -31,12 +31,12 @@ public struct FrostFsReplica : IEquatable<FrostFsReplica>
public readonly uint CountNodes() public readonly uint CountNodes()
{ {
return Count != 0 ? (uint)Count : EcDataCount + EcParityCount; return Count != 0 ? Count : EcDataCount + EcParityCount;
} }
public override readonly int GetHashCode() public override readonly int GetHashCode()
{ {
return (Count + Selector.GetHashCode()) ^ (int)EcDataCount ^ (int)EcParityCount; return Count.GetHashCode() ^ Selector.GetHashCode() ^ (int)EcDataCount ^ (int)EcParityCount;
} }
public static bool operator ==(FrostFsReplica left, FrostFsReplica right) public static bool operator ==(FrostFsReplica left, FrostFsReplica right)

View file

@ -3,12 +3,12 @@ using FrostFS.SDK.Client.Mappers.GRPC;
namespace FrostFS.SDK; namespace FrostFS.SDK;
public class FrostFsVersion(int major, int minor) public class FrostFsVersion(uint major, uint minor)
{ {
private Version? version; private Version? version;
public int Major { get; set; } = major; public uint Major { get; set; } = major;
public int Minor { get; set; } = minor; public uint Minor { get; set; } = minor;
internal Version VersionID internal Version VersionID
{ {

View file

@ -1,10 +1,10 @@
namespace FrostFS.SDK; namespace FrostFS.SDK;
public class MetaHeader(FrostFsVersion version, int epoch, int ttl) public class MetaHeader(FrostFsVersion version, ulong epoch, uint ttl)
{ {
public FrostFsVersion Version { get; set; } = version; public FrostFsVersion Version { get; set; } = version;
public int Epoch { get; set; } = epoch; public ulong Epoch { get; set; } = epoch;
public int Ttl { get; set; } = ttl; public uint Ttl { get; set; } = ttl;
public static MetaHeader Default() public static MetaHeader Default()
{ {

View file

@ -295,86 +295,88 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
internal async Task<FrostFsObjectId> PatchObjectAsync(PrmObjectPatch args, CallContext ctx) internal async Task<FrostFsObjectId> PatchObjectAsync(PrmObjectPatch args, CallContext ctx)
{ {
var chunkSize = args.MaxChunkLength; var chunkSize = args.MaxChunkLength;
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; var address = new Address
try
{ {
chunkBuffer = ArrayPool<byte>.Shared.Rent(chunkSize); ObjectId = args.Address.ObjectId,
ContainerId = args.Address.ContainerId
};
bool isFirstChunk = true; if (args.Payload != null && args.Payload.Length > 0)
ulong currentPos = args.Range.Offset; {
byte[]? chunkBuffer = null;
var address = new Address try
{ {
ObjectId = args.Address.ObjectId, chunkBuffer = ArrayPool<byte>.Shared.Rent(chunkSize);
ContainerId = args.Address.ContainerId
};
while (true) bool isFirstChunk = true;
{ ulong currentPos = args.Range.Offset;
var bytesCount = await payload.ReadAsync(chunkBuffer, 0, chunkSize, ctx.CancellationToken).ConfigureAwait(false);
if (bytesCount == 0) while (true)
{ {
break; var bytesCount = await args.Payload.ReadAsync(chunkBuffer, 0, chunkSize, ctx.CancellationToken).ConfigureAwait(false);
}
var request = new PatchRequest() if (bytesCount == 0)
{
Body = new()
{ {
Address = address, break;
Patch = new PatchRequest.Types.Body.Types.Patch }
PatchRequest request;
if (isFirstChunk)
{
request = await CreateFirstRequest(args, ctx, address).ConfigureAwait(false);
request.Body.Patch = new PatchRequest.Types.Body.Types.Patch
{ {
Chunk = UnsafeByteOperations.UnsafeWrap(chunkBuffer.AsMemory(0, bytesCount)), Chunk = UnsafeByteOperations.UnsafeWrap(chunkBuffer.AsMemory(0, bytesCount)),
SourceRange = new Range { Offset = currentPos, Length = (ulong)bytesCount } SourceRange = new Range { Offset = currentPos, Length = (ulong)bytesCount }
} };
isFirstChunk = false;
} }
}; else
if (isFirstChunk)
{
var sessionToken = args.SessionToken ?? await GetDefaultSession(args, ctx).ConfigureAwait(false);
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 = new PatchRequest()
{ {
request.Body.NewAttributes.Add(attr.ToMessage()); Body = new()
request.Body.ReplaceAttributes = args.ReplaceAttributes; {
} Address = address,
Patch = new PatchRequest.Types.Body.Types.Patch
{
Chunk = UnsafeByteOperations.UnsafeWrap(chunkBuffer.AsMemory(0, bytesCount)),
SourceRange = new Range { Offset = currentPos, Length = (ulong)bytesCount }
}
}
};
request.AddMetaHeader(args.XHeaders);
} }
isFirstChunk = false; request.Sign(ClientContext.Key);
await call.RequestStream.WriteAsync(request).ConfigureAwait(false);
currentPos += (ulong)bytesCount;
} }
else }
finally
{
if (chunkBuffer != null)
{ {
request.AddMetaHeader(args.XHeaders); ArrayPool<byte>.Shared.Return(chunkBuffer);
} }
request.Sign(ClientContext.Key);
await call.RequestStream.WriteAsync(request).ConfigureAwait(false);
currentPos += (ulong)bytesCount;
} }
} }
finally else if (args.NewAttributes != null && args.NewAttributes.Length > 0)
{ {
if (chunkBuffer != null) PatchRequest request = await CreateFirstRequest(args, ctx, address).ConfigureAwait(false);
{
ArrayPool<byte>.Shared.Return(chunkBuffer); request.Sign(ClientContext.Key);
}
await call.RequestStream.WriteAsync(request).ConfigureAwait(false);
} }
await call.RequestStream.CompleteAsync().ConfigureAwait(false); await call.RequestStream.CompleteAsync().ConfigureAwait(false);
@ -383,9 +385,36 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
Verifier.CheckResponse(response); Verifier.CheckResponse(response);
return response.Body.ObjectId.ToModel(); return response.Body.ObjectId.ToModel();
async Task<PatchRequest> CreateFirstRequest(PrmObjectPatch args, CallContext ctx, Address address)
{
var body = new PatchRequest.Types.Body() { Address = address };
if (args.NewAttributes != null)
{
body.ReplaceAttributes = args.ReplaceAttributes;
foreach (var attr in args.NewAttributes!)
{
body.NewAttributes.Add(attr.ToMessage());
}
}
var request = new PatchRequest() { Body = body };
var sessionToken = args.SessionToken ?? await GetDefaultSession(args, ctx).ConfigureAwait(false);
var protoToken = sessionToken.CreateObjectTokenContext(
address,
ObjectSessionContext.Types.Verb.Patch,
ClientContext.Key);
request.AddMetaHeader(args.XHeaders, protoToken);
return request;
}
} }
internal async Task<FrostFsObjectId> PutClientCutObjectAsync(PrmObjectClientCutPut args, CallContext ctx) internal async Task<FrostFsObjectId> PutClientCutObjectAsync(PrmObjectClientCutPut args, CallContext ctx)
{ {
if (args.Payload == null) if (args.Payload == null)
throw new ArgumentException(nameof(args.Payload)); throw new ArgumentException(nameof(args.Payload));
@ -582,8 +611,10 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
var restPart = (fullLength % (ulong)partSize) > 0 ? 1 : 0; var restPart = (fullLength % (ulong)partSize) > 0 ? 1 : 0;
var objectsCount = fullLength > 0 ? (int)(fullLength / (ulong)partSize) + restPart : 0; var objectsCount = fullLength > 0 ? (int)(fullLength / (ulong)partSize) + restPart : 0;
progressInfo ??= new UploadProgressInfo(Guid.NewGuid(), objectsCount);
// if the object fits one part, it can be loaded as non-complex object, but if it is not upload resuming // if the object fits one part, it can be loaded as non-complex object, but if it is not upload resuming
if (objectsCount == 1 && progressInfo != null && progressInfo.GetLast().Length == 0) if (objectsCount == 1 && progressInfo.GetLast().Length == 0)
{ {
args.PutObjectContext.MaxObjectSizeCache = partSize; args.PutObjectContext.MaxObjectSizeCache = partSize;
args.PutObjectContext.FullLength = fullLength; args.PutObjectContext.FullLength = fullLength;
@ -591,8 +622,6 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
return singlePartResult.ObjectId; return singlePartResult.ObjectId;
} }
progressInfo ??= new UploadProgressInfo(Guid.NewGuid(), objectsCount);
var remain = fullLength; var remain = fullLength;
byte[]? buffer = null; byte[]? buffer = null;
@ -659,7 +688,9 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
offset += size; offset += size;
if (i < objectsCount) if (i < objectsCount)
{
continue; continue;
}
// Once all parts of the object are uploaded, they must be linked into a single entity // Once all parts of the object are uploaded, they must be linked into a single entity
var linkObject = new FrostFsLinkObject(args.Header.ContainerId, progressInfo.SplitId, parentHeader!, [.. progressInfo.GetParts().Select(p => p.ObjectId)]); var linkObject = new FrostFsLinkObject(args.Header.ContainerId, progressInfo.SplitId, parentHeader!, [.. progressInfo.GetParts().Select(p => p.ObjectId)]);

View file

@ -1,7 +1,7 @@
using System.Reflection; using System.Reflection;
[assembly: AssemblyCompany("TrueCloudLab")] [assembly: AssemblyCompany("TrueCloudLab")]
[assembly: AssemblyFileVersion("1.0.6.0")] [assembly: AssemblyFileVersion("1.0.7.0")]
[assembly: AssemblyProduct("FrostFS.SDK.Cryptography")] [assembly: AssemblyProduct("FrostFS.SDK.Cryptography")]
[assembly: AssemblyTitle("FrostFS.SDK.Cryptography")] [assembly: AssemblyTitle("FrostFS.SDK.Cryptography")]
[assembly: AssemblyVersion("1.0.6.0")] [assembly: AssemblyVersion("1.0.7.0")]

View file

@ -5,7 +5,7 @@
<LangVersion>12.0</LangVersion> <LangVersion>12.0</LangVersion>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<PackageId>FrostFS.SDK.Cryptography</PackageId> <PackageId>FrostFS.SDK.Cryptography</PackageId>
<Version>1.0.6</Version> <Version>1.0.7</Version>
<Description> <Description>
Cryptography tools for C# SDK Cryptography tools for C# SDK
</Description> </Description>

View file

@ -1,7 +1,7 @@
using System.Reflection; using System.Reflection;
[assembly: AssemblyCompany("TrueCloudLab")] [assembly: AssemblyCompany("TrueCloudLab")]
[assembly: AssemblyFileVersion("1.0.6.0")] [assembly: AssemblyFileVersion("1.0.7.0")]
[assembly: AssemblyProduct("FrostFS.SDK.Protos")] [assembly: AssemblyProduct("FrostFS.SDK.Protos")]
[assembly: AssemblyTitle("FrostFS.SDK.Protos")] [assembly: AssemblyTitle("FrostFS.SDK.Protos")]
[assembly: AssemblyVersion("1.0.6.0")] [assembly: AssemblyVersion("1.0.7.0")]

View file

@ -5,7 +5,7 @@
<LangVersion>12.0</LangVersion> <LangVersion>12.0</LangVersion>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<PackageId>FrostFS.SDK.Protos</PackageId> <PackageId>FrostFS.SDK.Protos</PackageId>
<Version>1.0.6</Version> <Version>1.0.7</Version>
<Description> <Description>
Protobuf client for C# SDK Protobuf client for C# SDK
</Description> </Description>

View file

@ -77,7 +77,7 @@ public class ContainerTests : SmokeTestsBase
Assert.Empty(container.PlacementPolicy.Value.Filters); Assert.Empty(container.PlacementPolicy.Value.Filters);
Assert.Single(container.PlacementPolicy.Value.Replicas); Assert.Single(container.PlacementPolicy.Value.Replicas);
Assert.Equal(3, container.PlacementPolicy.Value.Replicas[0].Count); Assert.Equal(3u, container.PlacementPolicy.Value.Replicas[0].Count);
Assert.Equal(0u, container.PlacementPolicy.Value.Replicas[0].EcParityCount); Assert.Equal(0u, container.PlacementPolicy.Value.Replicas[0].EcParityCount);
Assert.Equal(0u, container.PlacementPolicy.Value.Replicas[0].EcDataCount); Assert.Equal(0u, container.PlacementPolicy.Value.Replicas[0].EcDataCount);
Assert.Equal("", container.PlacementPolicy.Value.Replicas[0].Selector); Assert.Equal("", container.PlacementPolicy.Value.Replicas[0].Selector);
@ -191,7 +191,7 @@ public class ContainerTests : SmokeTestsBase
Assert.Empty(subFilter.Filters); Assert.Empty(subFilter.Filters);
Assert.Single(container.PlacementPolicy.Value.Replicas); Assert.Single(container.PlacementPolicy.Value.Replicas);
Assert.Equal(1, container.PlacementPolicy.Value.Replicas[0].Count); Assert.Equal(1u, container.PlacementPolicy.Value.Replicas[0].Count);
Assert.Equal(0u, container.PlacementPolicy.Value.Replicas[0].EcParityCount); Assert.Equal(0u, container.PlacementPolicy.Value.Replicas[0].EcParityCount);
Assert.Equal(0u, container.PlacementPolicy.Value.Replicas[0].EcDataCount); Assert.Equal(0u, container.PlacementPolicy.Value.Replicas[0].EcDataCount);
Assert.Equal("", container.PlacementPolicy.Value.Replicas[0].Selector); Assert.Equal("", container.PlacementPolicy.Value.Replicas[0].Selector);

View file

@ -29,8 +29,8 @@ public class InterceptorTests() : SmokeTestsBase
Assert.True(callbackInvoked); Assert.True(callbackInvoked);
Assert.True(interceptorInvoked); Assert.True(interceptorInvoked);
Assert.Equal(2, result.Version.Major); Assert.Equal(2u, result.Version.Major);
Assert.Equal(13, result.Version.Minor); Assert.Equal(13u, result.Version.Minor);
Assert.Equal(NodeState.Online, result.State); Assert.Equal(NodeState.Online, result.State);
Assert.Equal(33, result.PublicKey.Length); Assert.Equal(33, result.PublicKey.Length);
Assert.NotNull(result.Addresses); Assert.NotNull(result.Addresses);

View file

@ -28,8 +28,8 @@ public class SmokeClientTests : SmokeTestsBase
var result = await client.GetNodeInfoAsync(default); var result = await client.GetNodeInfoAsync(default);
Assert.Equal(2, result.Version.Major); Assert.Equal(2u, result.Version.Major);
Assert.Equal(13, result.Version.Minor); Assert.Equal(13u, result.Version.Minor);
Assert.Equal(NodeState.Online, result.State); Assert.Equal(NodeState.Online, result.State);
Assert.Equal(33, result.PublicKey.Length); Assert.Equal(33, result.PublicKey.Length);
Assert.Single(result.Addresses); Assert.Single(result.Addresses);
@ -103,8 +103,8 @@ public class SmokeClientTests : SmokeTestsBase
Assert.True(callbackInvoked); Assert.True(callbackInvoked);
Assert.True(interceptorInvoked); Assert.True(interceptorInvoked);
Assert.Equal(2, result.Version.Major); Assert.Equal(2u, result.Version.Major);
Assert.Equal(13, result.Version.Minor); Assert.Equal(13u, result.Version.Minor);
Assert.Equal(NodeState.Online, result.State); Assert.Equal(NodeState.Online, result.State);
Assert.Equal(33, result.PublicKey.Length); Assert.Equal(33, result.PublicKey.Length);
Assert.NotNull(result.Addresses); Assert.NotNull(result.Addresses);

View file

@ -26,7 +26,7 @@ public class ObjectTests(ITestOutputHelper testOutputHelper) : SmokeTestsBase
[InlineData(false, 2, 3)] [InlineData(false, 2, 3)]
[InlineData(true, 2, 1)] [InlineData(true, 2, 1)]
[InlineData(false, 2, 1)] [InlineData(false, 2, 1)]
public async void FullScenario(bool unique, uint backupFactor, int replicas) public async void FullScenario(bool unique, uint backupFactor, uint replicas)
{ {
var client = FrostFSClient.GetInstance(ClientOptions, GrpcChannel); var client = FrostFSClient.GetInstance(ClientOptions, GrpcChannel);
_testOutputHelper.WriteLine("client created"); _testOutputHelper.WriteLine("client created");
@ -121,9 +121,16 @@ public class ObjectTests(ITestOutputHelper testOutputHelper) : SmokeTestsBase
await ValidateFilters(client, containerId, objectId, null, (ulong)bytes.Length); await ValidateFilters(client, containerId, objectId, null, (ulong)bytes.Length);
_testOutputHelper.WriteLine($"\tfilters validated"); _testOutputHelper.WriteLine($"\tfilters validated");
if (type != clientCut) if (type != clientCut && bytes.Length > 1024 + 64 && bytes.Length < 20 * 1024 * 1024)
{ {
await ValidatePatch(client, containerId, bytes, objectId); // patch payload only
await ValidatePatch(client, containerId, bytes, true, objectId, [], false);
// patch attributes only
await ValidatePatch(client, containerId, bytes, false, objectId, [new("a1", "v1"), new("a2", "v2")], false);
// patch payload and attributes
await ValidatePatch(client, containerId, bytes, true, objectId, [new("a3", "v3"), new("a4", "v4")], true);
_testOutputHelper.WriteLine($"\tpatch validated"); _testOutputHelper.WriteLine($"\tpatch validated");
} }
@ -199,51 +206,73 @@ public class ObjectTests(ITestOutputHelper testOutputHelper) : SmokeTestsBase
_testOutputHelper.WriteLine($"\t\trange {range.Offset};{range.Length} validated"); _testOutputHelper.WriteLine($"\t\trange {range.Offset};{range.Length} validated");
} }
private static async Task ValidatePatch(IFrostFSClient client, FrostFsContainerId containerId, byte[] bytes, FrostFsObjectId objectId) private static async Task ValidatePatch(
IFrostFSClient client,
FrostFsContainerId containerId,
byte[] bytes,
bool patchPayload,
FrostFsObjectId objectId,
FrostFsAttributePair[] attributes,
bool replaceAttributes)
{ {
if (bytes.Length < 1024 + 64 || bytes.Length > 5900) byte[]? patch = null;
return; FrostFsRange range = new();
if (patchPayload)
var patch = new byte[1024];
for (int i = 0; i < patch.Length; i++)
{ {
patch[i] = 32; patch = new byte[1024];
} for (int i = 0; i < patch.Length; i++)
{
patch[i] = 32;
}
var range = new FrostFsRange(64, (ulong)patch.Length); range = new FrostFsRange(64, (ulong)patch.Length);
}
var patchParams = new PrmObjectPatch( var patchParams = new PrmObjectPatch(
new FrostFsAddress(containerId, objectId), new FrostFsAddress(containerId, objectId),
payload: new MemoryStream(patch), payload: new MemoryStream(patch ?? []),
maxChunkLength: 1024, maxChunkLength: 1024,
range: range); range: range,
replaceAttributes: replaceAttributes,
newAttributes: attributes);
var newIbjId = await client.PatchObjectAsync(patchParams, default); var newIbjId = await client.PatchObjectAsync(patchParams, default);
var @object = await client.GetObjectAsync(new PrmObjectGet(containerId, newIbjId), default); var @object = await client.GetObjectAsync(new PrmObjectGet(containerId, newIbjId), default);
var downloadedBytes = new byte[@object.Header.PayloadLength]; if (patchPayload)
MemoryStream ms = new(downloadedBytes);
ReadOnlyMemory<byte>? chunk;
while ((chunk = await @object.ObjectReader!.ReadChunk()) != null)
{ {
ms.Write(chunk.Value.Span); var downloadedBytes = new byte[@object.Header.PayloadLength];
MemoryStream ms = new(downloadedBytes);
ReadOnlyMemory<byte>? chunk;
while ((chunk = await @object.ObjectReader!.ReadChunk()) != null)
{
ms.Write(chunk.Value.Span);
}
for (int i = 0; i < (int)range.Offset; i++)
Assert.Equal(downloadedBytes[i], bytes[i]);
var rangeEnd = range.Offset + range.Length;
for (int i = (int)range.Offset; i < (int)rangeEnd; i++)
Assert.Equal(downloadedBytes[i], patch[i - (int)range.Offset]);
for (int i = (int)rangeEnd; i < bytes.Length; i++)
Assert.Equal(downloadedBytes[i], bytes[i]);
} }
for (int i = 0; i < (int)range.Offset; i++) if (attributes != null && attributes.Length > 0)
Assert.Equal(downloadedBytes[i], bytes[i]); {
foreach (var newAttr in attributes)
var rangeEnd = range.Offset + range.Length; {
var i = @object!.Header!.Attributes!.Count(p => p.Key == newAttr.Key && p.Value == newAttr.Value);
for (int i = (int)range.Offset; i < (int)rangeEnd; i++) Assert.Equal(1, i);
Assert.Equal(downloadedBytes[i], patch[i - (int)range.Offset]); }
}
for (int i = (int)rangeEnd; i < bytes.Length; i++)
Assert.Equal(downloadedBytes[i], bytes[i]);
} }
private async Task ValidateFilters(IFrostFSClient client, FrostFsContainerId containerId, FrostFsObjectId objectId, SplitId? splitId, ulong length) private async Task ValidateFilters(IFrostFSClient client, FrostFsContainerId containerId, FrostFsObjectId objectId, SplitId? splitId, ulong length)
{ {
var ecdsaKey = keyString.LoadWif(); var ecdsaKey = keyString.LoadWif();
@ -338,7 +367,6 @@ public class ObjectTests(ITestOutputHelper testOutputHelper) : SmokeTestsBase
Assert.Null(objHeader.Split); Assert.Null(objHeader.Split);
} }
private static async Task<FrostFsObjectId> CreateObjectServerCut(IFrostFSClient client, FrostFsContainerId containerId, byte[] bytes) private static async Task<FrostFsObjectId> CreateObjectServerCut(IFrostFSClient client, FrostFsContainerId containerId, byte[] bytes)
{ {
var header = new FrostFsObjectHeader( var header = new FrostFsObjectHeader(

View file

@ -14,7 +14,7 @@ public class ContainerTest : ContainerTestsBase
[Theory] [Theory]
[InlineData(1, "test", 0, 0)] [InlineData(1, "test", 0, 0)]
public void ReplicaToMessagelTest(int count, string selector, uint ecDataCount, uint ecParityCount) public void ReplicaToMessagelTest(uint count, string selector, uint ecDataCount, uint ecParityCount)
{ {
FrostFsReplica replica = new() FrostFsReplica replica = new()
{ {
@ -26,7 +26,7 @@ public class ContainerTest : ContainerTestsBase
Replica message = replica.ToMessage(); Replica message = replica.ToMessage();
Assert.Equal((uint)count, message.Count); Assert.Equal(count, message.Count);
Assert.Equal(selector, message.Selector); Assert.Equal(selector, message.Selector);
Assert.Equal(ecDataCount, message.EcDataCount); Assert.Equal(ecDataCount, message.EcDataCount);
Assert.Equal(ecParityCount, message.EcParityCount); Assert.Equal(ecParityCount, message.EcParityCount);

View file

@ -69,13 +69,13 @@ public class PlacementPolicyTests : NetworkTestsBase
var rep0 = result.Replicas[0]; var rep0 = result.Replicas[0];
Assert.Equal(2u, rep0.EcDataCount); Assert.Equal(2u, rep0.EcDataCount);
Assert.Equal(3u, rep0.EcParityCount); Assert.Equal(3u, rep0.EcParityCount);
Assert.Equal(4, rep0.Count); Assert.Equal(4u, rep0.Count);
Assert.Equal("selector1", rep0.Selector); Assert.Equal("selector1", rep0.Selector);
var rep1 = result.Replicas[1]; var rep1 = result.Replicas[1];
Assert.Equal(5u, rep1.EcDataCount); Assert.Equal(5u, rep1.EcDataCount);
Assert.Equal(6u, rep1.EcParityCount); Assert.Equal(6u, rep1.EcParityCount);
Assert.Equal(7, rep1.Count); Assert.Equal(7u, rep1.Count);
Assert.Equal("selector2", rep1.Selector); Assert.Equal("selector2", rep1.Selector);
var f0 = result.Filters[0]; var f0 = result.Filters[0];
@ -126,7 +126,7 @@ public class PlacementPolicyTests : NetworkTestsBase
FrostFsReplica model = replica.ToModel(); FrostFsReplica model = replica.ToModel();
Assert.Equal(count, (uint)model.Count); Assert.Equal(count, model.Count);
Assert.Equal(selector, model.Selector); Assert.Equal(selector, model.Selector);
Assert.Equal(ecDataCount, model.EcDataCount); Assert.Equal(ecDataCount, model.EcDataCount);
Assert.Equal(ecParityCount, model.EcParityCount); Assert.Equal(ecParityCount, model.EcParityCount);
@ -140,7 +140,7 @@ public class PlacementPolicyTests : NetworkTestsBase
[InlineData(1, " ", 2, 3)] [InlineData(1, " ", 2, 3)]
[InlineData(10, "!", 0, 0)] [InlineData(10, "!", 0, 0)]
[InlineData(1, "123", 0, 0)] [InlineData(1, "123", 0, 0)]
public void ReplicaToMessagelTest(int count, string selector, uint ecDataCount, uint ecParityCount) public void ReplicaToMessagelTest(uint count, string selector, uint ecDataCount, uint ecParityCount)
{ {
FrostFsReplica replica = new () FrostFsReplica replica = new ()
{ {
@ -152,7 +152,7 @@ public class PlacementPolicyTests : NetworkTestsBase
Replica message = replica.ToMessage(); Replica message = replica.ToMessage();
Assert.Equal((uint)count, message.Count); Assert.Equal(count, message.Count);
Assert.Equal(selector, message.Selector); Assert.Equal(selector, message.Selector);
Assert.Equal(ecDataCount, message.EcDataCount); Assert.Equal(ecDataCount, message.EcDataCount);
Assert.Equal(ecParityCount, message.EcParityCount); Assert.Equal(ecParityCount, message.EcParityCount);
@ -235,11 +235,11 @@ public class PlacementPolicyTests : NetworkTestsBase
Assert.Single(message.Filters); Assert.Single(message.Filters);
var subfilter = message.Filters[0]; var grpcFilter = message.Filters[0];
Assert.Equal(name, subfilter.Name); Assert.Equal(name, grpcFilter.Name);
Assert.Equal(key, subfilter.Key); Assert.Equal(key, grpcFilter.Key);
Assert.Equal(operation, (int)subfilter.Op); Assert.Equal(operation, (int)grpcFilter.Op);
Assert.Equal(value, subfilter.Value); Assert.Equal(value, grpcFilter.Value);
} }
[Fact] [Fact]
@ -265,11 +265,11 @@ public class PlacementPolicyTests : NetworkTestsBase
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
{ {
var subfilter = message.Filters[i]; var grpcFilter = message.Filters[i];
Assert.Equal(names[i], subfilter.Name); Assert.Equal(names[i], grpcFilter.Name);
Assert.Equal(keys[i], subfilter.Key); Assert.Equal(keys[i], grpcFilter.Key);
Assert.Equal(operations[i], (int)subfilter.Op); Assert.Equal(operations[i], (int)grpcFilter.Op);
Assert.Equal(values[i], subfilter.Value); Assert.Equal(values[i], grpcFilter.Value);
} }
} }

View file

@ -248,12 +248,12 @@ public class FilterDto
Key ?? string.Empty, Key ?? string.Empty,
(int)Op, (int)Op,
Value ?? string.Empty, Value ?? string.Empty,
Filters != null ? Filters.Select(f => f.Filter).ToArray() : []); Filters != null ? [.. Filters.Select(f => f.Filter)] : []);
} }
public class ReplicaDto public class ReplicaDto
{ {
public int Count { get; set; } public uint Count { get; set; }
public string? Selector { get; set; } public string? Selector { get; set; }
} }