[#25] Client: Implement Patch and Range methods
All checks were successful
DCO / DCO (pull_request) Successful in 47s
All checks were successful
DCO / DCO (pull_request) Successful in 47s
Signed-off-by: Pavel Gross <p.gross@yadro.com>
This commit is contained in:
parent
bff8d67867
commit
003b7fdfdd
51 changed files with 1338 additions and 137 deletions
43
src/FrostFS.SDK.Tests/Mocks/AsyncStreamRangeReaderMock.cs
Normal file
43
src/FrostFS.SDK.Tests/Mocks/AsyncStreamRangeReaderMock.cs
Normal file
|
@ -0,0 +1,43 @@
|
|||
using System.Security.Cryptography;
|
||||
|
||||
using FrostFS.Object;
|
||||
using FrostFS.SDK.ClientV2;
|
||||
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
using FrostFS.Session;
|
||||
|
||||
using Google.Protobuf;
|
||||
|
||||
using Grpc.Core;
|
||||
|
||||
namespace FrostFS.SDK.Tests;
|
||||
|
||||
public class AsyncStreamRangeReaderMock(string key, byte[] response) : ServiceBase(key), IAsyncStreamReader<GetRangeResponse>
|
||||
{
|
||||
private readonly byte[] _response = response;
|
||||
|
||||
public GetRangeResponse Current
|
||||
{
|
||||
get
|
||||
{
|
||||
var response = new GetRangeResponse
|
||||
{
|
||||
Body = new GetRangeResponse.Types.Body
|
||||
{
|
||||
Chunk = ByteString.CopyFrom(_response)
|
||||
},
|
||||
MetaHeader = new ResponseMetaHeader()
|
||||
};
|
||||
|
||||
response.VerifyHeader = GetResponseVerificationHeader(response);
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
public Task<bool> MoveNext(CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ using FrostFS.Object;
|
|||
using FrostFS.SDK.ClientV2;
|
||||
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
using FrostFS.Session;
|
||||
|
||||
using Google.Protobuf;
|
||||
|
||||
|
@ -16,6 +17,32 @@ namespace FrostFS.SDK.Tests;
|
|||
|
||||
public class ObjectMocker(string key) : ObjectServiceBase(key)
|
||||
{
|
||||
public FrostFsObjectId? ObjectId { get; set; }
|
||||
|
||||
public FrostFsObjectHeader? ObjectHeader { get; set; }
|
||||
|
||||
public Header? HeadResponse { get; set; }
|
||||
|
||||
public Collection<byte[]>? ResultObjectIds { get; } = [];
|
||||
|
||||
public ClientStreamWriter? ClientStreamWriter { get; } = new();
|
||||
|
||||
public PatchStreamWriter? PatchStreamWriter { get; } = new();
|
||||
|
||||
public Collection<PutSingleRequest> PutSingleRequests { get; } = [];
|
||||
|
||||
public Collection<DeleteRequest> DeleteRequests { get; } = [];
|
||||
|
||||
public Collection<HeadRequest> HeadRequests { get; } = [];
|
||||
|
||||
public byte[] RangeResponse { get; set; } = [];
|
||||
|
||||
public GetRangeRequest? GetRangeRequest { get; set; }
|
||||
|
||||
public GetRangeHashRequest? GetRangeHashRequest { get; set; }
|
||||
|
||||
public Collection<ByteString> RangeHashResponses { get; } = [];
|
||||
|
||||
public override Mock<ObjectService.ObjectServiceClient> GetMock()
|
||||
{
|
||||
var mock = new Mock<ObjectService.ObjectServiceClient>();
|
||||
|
@ -189,23 +216,88 @@ public class ObjectMocker(string key) : ObjectServiceBase(key)
|
|||
});
|
||||
}
|
||||
|
||||
mock.Setup(x => x.GetRange(
|
||||
It.IsAny<GetRangeRequest>(),
|
||||
It.IsAny<Metadata>(),
|
||||
It.IsAny<DateTime?>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.Returns((GetRangeRequest r, Metadata m, DateTime? dt, CancellationToken ct) =>
|
||||
{
|
||||
Verifier.CheckRequest(r);
|
||||
|
||||
GetRangeRequest = r;
|
||||
|
||||
return new AsyncServerStreamingCall<GetRangeResponse>(
|
||||
new AsyncStreamRangeReaderMock(StringKey, RangeResponse),
|
||||
Task.FromResult(ResponseMetaData),
|
||||
() => new Grpc.Core.Status(StatusCode.OK, string.Empty),
|
||||
() => ResponseMetaData,
|
||||
() => { });
|
||||
});
|
||||
|
||||
mock.Setup(x => x.GetRangeHashAsync(
|
||||
It.IsAny<GetRangeHashRequest>(),
|
||||
It.IsAny<Metadata>(),
|
||||
It.IsAny<DateTime?>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.Returns((GetRangeHashRequest r, Metadata m, DateTime? dt, CancellationToken ct) =>
|
||||
{
|
||||
Verifier.CheckRequest(r);
|
||||
|
||||
GetRangeHashRequest = r;
|
||||
|
||||
var response = new GetRangeHashResponse
|
||||
{
|
||||
Body = new GetRangeHashResponse.Types.Body(),
|
||||
MetaHeader = ResponseMetaHeader
|
||||
};
|
||||
|
||||
if (RangeHashResponses != null)
|
||||
{
|
||||
foreach (var hash in RangeHashResponses)
|
||||
{
|
||||
response.Body.HashList.Add(hash);
|
||||
}
|
||||
}
|
||||
|
||||
response.VerifyHeader = GetResponseVerificationHeader(response);
|
||||
|
||||
return new AsyncUnaryCall<GetRangeHashResponse>(
|
||||
Task.FromResult(response),
|
||||
Task.FromResult(ResponseMetaData),
|
||||
() => new Grpc.Core.Status(StatusCode.OK, string.Empty),
|
||||
() => ResponseMetaData,
|
||||
() => { });
|
||||
});
|
||||
|
||||
|
||||
mock.Setup(x => x.Patch(
|
||||
It.IsAny<Metadata>(),
|
||||
It.IsAny<DateTime?>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.Returns((Metadata m, DateTime? dt, CancellationToken ct) =>
|
||||
{
|
||||
var patchResponse = new PatchResponse
|
||||
{
|
||||
Body = new PatchResponse.Types.Body
|
||||
{
|
||||
ObjectId = new Refs.ObjectID { Value = ByteString.CopyFrom(SHA256.HashData([1,2,3])) },
|
||||
},
|
||||
MetaHeader = ResponseMetaHeader
|
||||
};
|
||||
|
||||
patchResponse.VerifyHeader = GetResponseVerificationHeader(patchResponse);
|
||||
|
||||
return new AsyncClientStreamingCall<PatchRequest, PatchResponse>(
|
||||
PatchStreamWriter!,
|
||||
Task.FromResult(patchResponse),
|
||||
Task.FromResult(ResponseMetaData),
|
||||
() => new Grpc.Core.Status(StatusCode.OK, string.Empty),
|
||||
() => ResponseMetaData,
|
||||
() => { });
|
||||
});
|
||||
|
||||
return mock;
|
||||
}
|
||||
|
||||
public FrostFsObjectId? ObjectId { get; set; }
|
||||
|
||||
public FrostFsObjectHeader? ObjectHeader { get; set; }
|
||||
|
||||
public Header? HeadResponse { get; set; }
|
||||
|
||||
public Collection<byte[]>? ResultObjectIds { get; } = [];
|
||||
|
||||
public ClientStreamWriter? ClientStreamWriter { get; private set; } = new();
|
||||
|
||||
public Collection<PutSingleRequest> PutSingleRequests { get; private set; } = [];
|
||||
|
||||
public Collection<DeleteRequest> DeleteRequests { get; private set; } = [];
|
||||
|
||||
public Collection<HeadRequest> HeadRequests { get; private set; } = [];
|
||||
}
|
||||
|
||||
|
|
36
src/FrostFS.SDK.Tests/Mocks/PatchStreamWriter.cs
Normal file
36
src/FrostFS.SDK.Tests/Mocks/PatchStreamWriter.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using System.Collections.ObjectModel;
|
||||
|
||||
using FrostFS.SDK.ProtosV2.Interfaces;
|
||||
|
||||
using Grpc.Core;
|
||||
|
||||
namespace FrostFS.SDK.Tests;
|
||||
|
||||
public class PatchStreamWriter : IClientStreamWriter<IRequest>
|
||||
{
|
||||
private WriteOptions? _options;
|
||||
|
||||
public Collection<IRequest> Messages { get; } = [];
|
||||
|
||||
public bool CompletedTask { get; private set; }
|
||||
|
||||
public WriteOptions? WriteOptions
|
||||
{
|
||||
get => _options;
|
||||
set => _options = value;
|
||||
}
|
||||
|
||||
public Task CompleteAsync()
|
||||
{
|
||||
CompletedTask = true;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task WriteAsync(IRequest message)
|
||||
{
|
||||
Object.PatchRequest pr = new((Object.PatchRequest)message);
|
||||
Messages.Add(pr);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,8 @@ using FrostFS.SDK.Cryptography;
|
|||
|
||||
using Google.Protobuf;
|
||||
|
||||
using static FrostFS.Object.ECInfo.Types;
|
||||
|
||||
namespace FrostFS.SDK.Tests;
|
||||
|
||||
[SuppressMessage("Reliability", "CA2007:Consider calling ConfigureAwait on the awaited task", Justification = "Default Value is correct for tests")]
|
||||
|
@ -223,4 +225,121 @@ public class ObjectTest : ObjectTestsBase
|
|||
|
||||
Assert.Null(response.Split);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void GetRangeTest()
|
||||
{
|
||||
Mocker.ResultObjectIds!.Add(SHA256.HashData([]));
|
||||
|
||||
Random rnd = new();
|
||||
var bytes = new byte[1024];
|
||||
rnd.NextBytes(bytes);
|
||||
|
||||
Mocker.RangeResponse = bytes;
|
||||
|
||||
Mocker.ObjectId = new ObjectID { Value = ByteString.CopyFrom(SHA256.HashData(Encoding.UTF8.GetBytes("test"))) }.ToModel();
|
||||
|
||||
var param = new PrmRangeGet(ContainerId, Mocker.ObjectId, new FrostFsRange(100, (ulong)Mocker.RangeResponse.Length));
|
||||
|
||||
var result = await GetClient().GetRangeAsync(param);
|
||||
|
||||
Assert.NotNull(Mocker.GetRangeRequest);
|
||||
|
||||
Assert.Equal(param.Range.Offset, Mocker.GetRangeRequest.Body.Range.Offset);
|
||||
Assert.Equal(param.Range.Length, Mocker.GetRangeRequest.Body.Range.Length);
|
||||
|
||||
Assert.NotNull(result);
|
||||
|
||||
var chunk = await result.ReadChunk();
|
||||
|
||||
var chunkBytes = chunk.Value.Span.ToArray();
|
||||
|
||||
Assert.Equal(chunkBytes.Length, Mocker.RangeResponse.Length);
|
||||
|
||||
Assert.Equal(SHA256.HashData(bytes), SHA256.HashData(Mocker.RangeResponse));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void GetRangeHashTest()
|
||||
{
|
||||
Mocker.ResultObjectIds!.Add(SHA256.HashData([]));
|
||||
|
||||
Random rnd = new();
|
||||
var bytes = new byte[1024];
|
||||
rnd.NextBytes(bytes);
|
||||
|
||||
var salt = new byte[32];
|
||||
rnd.NextBytes(salt);
|
||||
|
||||
var hash = new byte[32];
|
||||
rnd.NextBytes(hash);
|
||||
|
||||
Mocker.RangeResponse = bytes;
|
||||
var len = (ulong)bytes.Length;
|
||||
|
||||
Mocker.RangeHashResponses.Add(ByteString.CopyFrom(hash));
|
||||
|
||||
Mocker.ObjectId = new ObjectID { Value = ByteString.CopyFrom(SHA256.HashData(Encoding.UTF8.GetBytes("test"))) }.ToModel();
|
||||
|
||||
var param = new PrmRangeHashGet(ContainerId, Mocker.ObjectId, [new FrostFsRange(100, len)], salt);
|
||||
|
||||
var result = await GetClient().GetRangeHashAsync(param);
|
||||
|
||||
Assert.NotNull(Mocker.GetRangeHashRequest);
|
||||
|
||||
Assert.Equal(param.Ranges[0].Offset, Mocker.GetRangeHashRequest.Body.Ranges[0].Offset);
|
||||
Assert.Equal(param.Ranges[0].Length, Mocker.GetRangeHashRequest.Body.Ranges[0].Length);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Single(result);
|
||||
|
||||
Assert.Equal(SHA256.HashData(hash), SHA256.HashData(result.First().ToArray()));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void PatchTest()
|
||||
{
|
||||
Mocker.ObjectId = new ObjectID { Value = ByteString.CopyFrom(SHA256.HashData(Encoding.UTF8.GetBytes("test"))) }.ToModel();
|
||||
|
||||
var address = new FrostFsAddress(ContainerId, Mocker.ObjectId);
|
||||
|
||||
Mocker.ResultObjectIds!.Add(SHA256.HashData([]));
|
||||
|
||||
Random rnd = new();
|
||||
var patch = new byte[32];
|
||||
rnd.NextBytes(patch);
|
||||
|
||||
var range = new FrostFsRange(8, (ulong)patch.Length);
|
||||
|
||||
var param = new PrmObjectPatch(address)
|
||||
{
|
||||
Payload = new MemoryStream(patch),
|
||||
MaxPayloadPatchChunkLength = 32,
|
||||
Range = range
|
||||
};
|
||||
|
||||
var result = await GetClient().PatchObjectAsync(param);
|
||||
|
||||
Assert.NotNull(result);
|
||||
|
||||
Assert.NotNull(result.Value);
|
||||
|
||||
Assert.NotNull(Mocker.PatchStreamWriter);
|
||||
Assert.Single(Mocker.PatchStreamWriter.Messages);
|
||||
|
||||
var sentMessages = Mocker.PatchStreamWriter!.Messages;
|
||||
|
||||
var body = sentMessages.First().GetBody() as Object.PatchRequest.Types.Body;
|
||||
|
||||
Assert.NotNull(body);
|
||||
|
||||
Assert.True(Mocker.PatchStreamWriter.CompletedTask);
|
||||
|
||||
Assert.Equal(address.ContainerId, body.Address.ContainerId);
|
||||
Assert.Equal(address.ObjectId, body.Address.ObjectId);
|
||||
|
||||
Assert.Equal(32, body.Patch.Chunk.Length);
|
||||
|
||||
Assert.Equal(SHA256.HashData(patch), SHA256.HashData(body.Patch.Chunk.ToArray()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -247,37 +247,108 @@ public class SmokeClientTests : SmokeTestsBase
|
|||
[InlineData(3 * 1024 * 1024)] // exactly one chunk size - 3MB
|
||||
[InlineData(6 * 1024 * 1024 + 100)]
|
||||
public async void SimpleScenarioTest(int objectSize)
|
||||
{
|
||||
using var client = FrostFSClient.GetSingleOwnerInstance(GetSingleOwnerOptions(this.keyString, this.url));
|
||||
|
||||
await Cleanup(client);
|
||||
|
||||
bool callbackInvoked = false;
|
||||
var ctx = new CallContext
|
||||
{
|
||||
// Timeout = TimeSpan.FromSeconds(20),
|
||||
Callback = new((CallStatistics cs) =>
|
||||
{
|
||||
callbackInvoked = true;
|
||||
Assert.True(cs.ElapsedMicroSeconds > 0);
|
||||
})
|
||||
};
|
||||
|
||||
var createContainerParam = new PrmContainerCreate(
|
||||
new FrostFsContainerInfo(new FrostFsPlacementPolicy(true, new FrostFsReplica(1)), [new("testKey", "testValue")]), ctx);
|
||||
|
||||
var createdContainer = await client.CreateContainerAsync(createContainerParam);
|
||||
|
||||
var container = await client.GetContainerAsync(new PrmContainerGet(createdContainer, ctx));
|
||||
Assert.NotNull(container);
|
||||
Assert.True(callbackInvoked);
|
||||
|
||||
var bytes = GetRandomBytes(objectSize);
|
||||
|
||||
var param = new PrmObjectPut(new CallContext
|
||||
{
|
||||
Callback = new((CallStatistics cs) => Assert.True(cs.ElapsedMicroSeconds > 0))
|
||||
})
|
||||
{
|
||||
Header = new FrostFsObjectHeader(
|
||||
containerId: createdContainer,
|
||||
type: FrostFsObjectType.Regular,
|
||||
[new FrostFsAttributePair("fileName", "test")]),
|
||||
Payload = new MemoryStream(bytes),
|
||||
ClientCut = false
|
||||
};
|
||||
|
||||
var objectId = await client.PutObjectAsync(param);
|
||||
|
||||
var filter = new FilterByAttributePair(FrostFsMatchType.Equals, "fileName", "test");
|
||||
|
||||
bool hasObject = false;
|
||||
await foreach (var objId in client.SearchObjectsAsync(new PrmObjectSearch(createdContainer) { Filters = [filter] }))
|
||||
{
|
||||
hasObject = true;
|
||||
|
||||
var objHeader = await client.GetObjectHeadAsync(new PrmObjectHeadGet(createdContainer, objectId));
|
||||
Assert.Equal((ulong)bytes.Length, objHeader.PayloadLength);
|
||||
Assert.NotNull(objHeader.Attributes);
|
||||
Assert.Single(objHeader.Attributes);
|
||||
Assert.Equal("fileName", objHeader.Attributes.First().Key);
|
||||
Assert.Equal("test", objHeader.Attributes.First().Value);
|
||||
}
|
||||
|
||||
Assert.True(hasObject);
|
||||
|
||||
var @object = await client.GetObjectAsync(new PrmObjectGet(createdContainer, objectId));
|
||||
|
||||
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 foreach (var _ in client.ListContainersAsync())
|
||||
{
|
||||
Assert.Fail("Containers exist");
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void PatchTest()
|
||||
{
|
||||
using var client = FrostFSClient.GetSingleOwnerInstance(GetSingleOwnerOptions(this.keyString, this.url));
|
||||
|
||||
await Cleanup(client);
|
||||
|
||||
bool callbackInvoked = false;
|
||||
var ctx = new CallContext
|
||||
{
|
||||
// Timeout = TimeSpan.FromSeconds(20),
|
||||
Callback = new((CallStatistics cs) =>
|
||||
{
|
||||
callbackInvoked = true;
|
||||
Assert.True(cs.ElapsedMicroSeconds > 0);
|
||||
})
|
||||
};
|
||||
|
||||
var createContainerParam = new PrmContainerCreate(
|
||||
new FrostFsContainerInfo(new FrostFsPlacementPolicy(true, new FrostFsReplica(1)), [new("testKey", "testValue")]), ctx);
|
||||
new FrostFsContainerInfo(new FrostFsPlacementPolicy(true, new FrostFsReplica(1)), [new("testKey", "testValue")]));
|
||||
|
||||
var createdContainer = await client.CreateContainerAsync(createContainerParam);
|
||||
|
||||
var container = await client.GetContainerAsync(new PrmContainerGet(createdContainer, ctx));
|
||||
var container = await client.GetContainerAsync(new PrmContainerGet(createdContainer));
|
||||
Assert.NotNull(container);
|
||||
Assert.True(callbackInvoked);
|
||||
|
||||
var bytes = GetRandomBytes(objectSize);
|
||||
|
||||
var param = new PrmObjectPut(new CallContext
|
||||
var bytes = new byte[1024];
|
||||
for (int i = 0; i < 1024; i++)
|
||||
{
|
||||
Callback = new((CallStatistics cs) => Assert.True(cs.ElapsedMicroSeconds > 0))
|
||||
})
|
||||
bytes[i] = (byte)31;
|
||||
}
|
||||
|
||||
var param = new PrmObjectPut
|
||||
{
|
||||
Header = new FrostFsObjectHeader(
|
||||
containerId: createdContainer,
|
||||
|
@ -289,24 +360,24 @@ public class SmokeClientTests : SmokeTestsBase
|
|||
|
||||
var objectId = await client.PutObjectAsync(param);
|
||||
|
||||
var filter = new FilterByAttributePair(FrostFsMatchType.Equals, "fileName", "test");
|
||||
|
||||
bool hasObject = false;
|
||||
await foreach (var objId in client.SearchObjectsAsync(new PrmObjectSearch(createdContainer) { Filters = [filter] }))
|
||||
var patch = new byte[16];
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
hasObject = true;
|
||||
|
||||
var objHeader = await client.GetObjectHeadAsync(new PrmObjectHeadGet(createdContainer, objectId));
|
||||
Assert.Equal((ulong)bytes.Length, objHeader.PayloadLength);
|
||||
Assert.NotNull(objHeader.Attributes);
|
||||
Assert.Single(objHeader.Attributes);
|
||||
Assert.Equal("fileName", objHeader.Attributes.First().Key);
|
||||
Assert.Equal("test", objHeader.Attributes.First().Value);
|
||||
patch[i] = (byte)32;
|
||||
}
|
||||
|
||||
Assert.True(hasObject);
|
||||
var range = new FrostFsRange(8, (ulong)patch.Length);
|
||||
|
||||
var @object = await client.GetObjectAsync(new PrmObjectGet(createdContainer, objectId));
|
||||
var patchParams = new PrmObjectPatch(new FrostFsAddress(createdContainer, objectId))
|
||||
{
|
||||
Payload = new MemoryStream(patch),
|
||||
MaxPayloadPatchChunkLength = 32,
|
||||
Range = range
|
||||
};
|
||||
|
||||
var newIbjId = await client.PatchObjectAsync(patchParams);
|
||||
|
||||
var @object = await client.GetObjectAsync(new PrmObjectGet(createdContainer, newIbjId));
|
||||
|
||||
var downloadedBytes = new byte[@object.Header.PayloadLength];
|
||||
MemoryStream ms = new(downloadedBytes);
|
||||
|
@ -317,8 +388,121 @@ public class SmokeClientTests : SmokeTestsBase
|
|||
ms.Write(chunk.Value.Span);
|
||||
}
|
||||
|
||||
Assert.Equal(SHA256.HashData(bytes), SHA256.HashData(downloadedBytes));
|
||||
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]);
|
||||
|
||||
await Cleanup(client);
|
||||
|
||||
await foreach (var _ in client.ListContainersAsync())
|
||||
{
|
||||
Assert.Fail("Containers exist");
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void RangeTest()
|
||||
{
|
||||
using var client = FrostFSClient.GetSingleOwnerInstance(GetSingleOwnerOptions(this.keyString, this.url));
|
||||
|
||||
await Cleanup(client);
|
||||
|
||||
var createContainerParam = new PrmContainerCreate(
|
||||
new FrostFsContainerInfo(new FrostFsPlacementPolicy(true, new FrostFsReplica(1)), [new("testKey", "testValue")]));
|
||||
|
||||
var createdContainer = await client.CreateContainerAsync(createContainerParam);
|
||||
|
||||
var container = await client.GetContainerAsync(new PrmContainerGet(createdContainer));
|
||||
Assert.NotNull(container);
|
||||
|
||||
var bytes = new byte[256];
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
bytes[i] = (byte)i;
|
||||
}
|
||||
|
||||
var param = new PrmObjectPut
|
||||
{
|
||||
Header = new FrostFsObjectHeader(
|
||||
containerId: createdContainer,
|
||||
type: FrostFsObjectType.Regular),
|
||||
Payload = new MemoryStream(bytes),
|
||||
ClientCut = false
|
||||
};
|
||||
|
||||
var objectId = await client.PutObjectAsync(param);
|
||||
|
||||
var rangeParam = new PrmRangeGet(createdContainer, objectId, new FrostFsRange(100, 64));
|
||||
|
||||
var rangeReader = await client.GetRangeAsync(rangeParam);
|
||||
|
||||
var downloadedBytes = new byte[rangeParam.Range.Length];
|
||||
MemoryStream ms = new(downloadedBytes);
|
||||
|
||||
ReadOnlyMemory<byte>? chunk = null;
|
||||
while ((chunk = await rangeReader!.ReadChunk()) != null)
|
||||
{
|
||||
ms.Write(chunk.Value.Span);
|
||||
}
|
||||
|
||||
Assert.Equal(SHA256.HashData(bytes.AsSpan().Slice(100, 64)), SHA256.HashData(downloadedBytes));
|
||||
|
||||
await Cleanup(client);
|
||||
|
||||
await foreach (var _ in client.ListContainersAsync())
|
||||
{
|
||||
Assert.Fail("Containers exist");
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void RangeHashTest()
|
||||
{
|
||||
using var client = FrostFSClient.GetSingleOwnerInstance(GetSingleOwnerOptions(this.keyString, this.url));
|
||||
|
||||
await Cleanup(client);
|
||||
|
||||
var createContainerParam = new PrmContainerCreate(
|
||||
new FrostFsContainerInfo(new FrostFsPlacementPolicy(true, new FrostFsReplica(1)), [new("testKey", "testValue")]));
|
||||
|
||||
var createdContainer = await client.CreateContainerAsync(createContainerParam);
|
||||
|
||||
var container = await client.GetContainerAsync(new PrmContainerGet(createdContainer));
|
||||
Assert.NotNull(container);
|
||||
|
||||
var bytes = new byte[256];
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
bytes[i] = (byte)i;
|
||||
}
|
||||
|
||||
var param = new PrmObjectPut
|
||||
{
|
||||
Header = new FrostFsObjectHeader(
|
||||
containerId: createdContainer,
|
||||
type: FrostFsObjectType.Regular),
|
||||
Payload = new MemoryStream(bytes),
|
||||
ClientCut = false
|
||||
};
|
||||
|
||||
var objectId = await client.PutObjectAsync(param);
|
||||
|
||||
var rangeParam = new PrmRangeHashGet(createdContainer, objectId, [ new FrostFsRange(100, 64)], bytes);
|
||||
|
||||
var hashes = await client.GetRangeHashAsync(rangeParam);
|
||||
|
||||
foreach (var hash in hashes)
|
||||
{
|
||||
var x = hash.Slice(0, 32).ToArray();
|
||||
}
|
||||
|
||||
await Cleanup(client);
|
||||
|
||||
await foreach (var _ in client.ListContainersAsync())
|
||||
|
|
|
@ -7,6 +7,8 @@ namespace FrostFS.SDK.SmokeTests;
|
|||
|
||||
public abstract class SmokeTestsBase
|
||||
{
|
||||
// internal readonly string keyString = "KzPXA6669m2pf18XmUdoR8MnP1pi1PMmefiFujStVFnv7WR5SRmK";
|
||||
|
||||
internal readonly string keyString = "KzPXA6669m2pf18XmUdoR8MnP1pi1PMmefiFujStVFnv7WR5SRmK";
|
||||
|
||||
internal readonly string url = "http://172.23.32.4:8080";
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue