Signed-off-by: Pavel Gross <p.gross@yadro.com>
This commit is contained in:
parent
ae67b12313
commit
fefa2da218
43 changed files with 884 additions and 477 deletions
|
@ -13,7 +13,6 @@ using Microsoft.Extensions.Options;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading.Tasks;
|
||||
using Version = FrostFS.SDK.ModelsV2.Version;
|
||||
|
||||
|
@ -168,7 +167,7 @@ public class Client : IFrostFSClient
|
|||
return service.GetObjectHeadAsync(containerId, objectId, ctx!);
|
||||
}
|
||||
|
||||
public Task<ModelsV2.Object> GetObjectAsync(ContainerId containerId, ObjectId objectId, Context? ctx = default)
|
||||
public Task<FrostFsObject> GetObjectAsync(ContainerId containerId, ObjectId objectId, Context? ctx = default)
|
||||
{
|
||||
var service = GetObjectService(ref ctx);
|
||||
return service.GetObjectAsync(containerId, objectId, ctx!);
|
||||
|
@ -180,7 +179,7 @@ public class Client : IFrostFSClient
|
|||
return service.PutObjectAsync(putObjectParameters, ctx!);
|
||||
}
|
||||
|
||||
public Task<ObjectId> PutSingleObjectAsync(ModelsV2.Object obj, Context? ctx = default)
|
||||
public Task<ObjectId> PutSingleObjectAsync(FrostFsObject obj, Context? ctx = default)
|
||||
{
|
||||
var service = GetObjectService(ref ctx);
|
||||
return service.PutSingleObjectAsync(obj, ctx!);
|
||||
|
@ -312,26 +311,21 @@ public class Client : IFrostFSClient
|
|||
|
||||
private static GrpcChannel InitGrpcChannel(string host, GrpcChannelOptions? channelOptions)
|
||||
{
|
||||
Uri uri;
|
||||
try
|
||||
{
|
||||
uri = new Uri(host);
|
||||
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)
|
||||
{
|
||||
var msg = $"Host '{host}' has invalid format. Error: {e.Message}";
|
||||
throw new ArgumentException(msg);
|
||||
throw new ArgumentException($"Host '{host}' has invalid format. Error: {e.Message}");
|
||||
}
|
||||
|
||||
if (channelOptions != null)
|
||||
{
|
||||
return GrpcChannel.ForAddress(uri, channelOptions);
|
||||
}
|
||||
|
||||
|
||||
return GrpcChannel.ForAddress(uri, new GrpcChannelOptions
|
||||
{
|
||||
HttpHandler = new HttpClientHandler()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,11 +34,11 @@ public interface IFrostFSClient : IDisposable
|
|||
#region Object
|
||||
Task<ObjectHeader> GetObjectHeadAsync(ContainerId containerId, ObjectId objectId, Context? context = default);
|
||||
|
||||
Task<ModelsV2.Object> GetObjectAsync(ContainerId containerId, ObjectId objectId, Context? context = default);
|
||||
Task<FrostFsObject> GetObjectAsync(ContainerId containerId, ObjectId objectId, Context? context = default);
|
||||
|
||||
Task<ObjectId> PutObjectAsync(PutObjectParameters putObjectParameters, Context? context = default);
|
||||
|
||||
Task<ObjectId> PutSingleObjectAsync(ModelsV2.Object obj, Context? context = default);
|
||||
Task<ObjectId> PutSingleObjectAsync(FrostFsObject obj, Context? context = default);
|
||||
|
||||
Task DeleteObjectAsync(ContainerId containerId, ObjectId objectId, Context? context = default);
|
||||
|
||||
|
|
|
@ -4,9 +4,9 @@ namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
|
|||
|
||||
public static class ObjectMapper
|
||||
{
|
||||
public static ModelsV2.Object ToModel(this Object.Object obj)
|
||||
public static FrostFsObject ToModel(this Object.Object obj)
|
||||
{
|
||||
return new ModelsV2.Object(
|
||||
return new FrostFsObject(
|
||||
ObjectId.FromHash(obj.ObjectId.Value.ToByteArray()),
|
||||
obj.Header.ToModel(),
|
||||
obj.Payload.ToByteArray());
|
||||
|
|
|
@ -44,7 +44,7 @@ public static class ObjectHeaderMapper
|
|||
SplitId = split.SplitId != null ? ByteString.CopyFrom(split.SplitId.ToBinary()) : null
|
||||
};
|
||||
|
||||
if (split.Children != null && split.Children.Any())
|
||||
if (split.Children != null && split.Children.Count != 0)
|
||||
head.Split.Children.AddRange(split.Children.Select(id => id.ToGrpcMessage()));
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ public static class ObjectHeaderMapper
|
|||
Previous = header.Split.Previous?.ToModel()
|
||||
};
|
||||
|
||||
if (header.Split.Children.Any())
|
||||
if (header.Split.Children.Count != 0)
|
||||
model.Split.Children.AddRange(header.Split.Children.Select(x => x.ToModel()));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
|
||||
using System;
|
||||
using Google.Protobuf;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2;
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
using System.Threading.Tasks;
|
||||
using FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
using FrostFS.Container;
|
||||
|
||||
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
using System.Collections.Generic;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2;
|
||||
|
||||
|
|
|
@ -51,10 +51,6 @@ internal class NetmapServiceProvider : ContextAccessor
|
|||
|
||||
var response = await netmapServiceClient.LocalNodeInfoAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
||||
|
||||
//var response = await Context.InvokeAsyncUnaryWithMetrics(() =>
|
||||
// netmapServiceClient.LocalNodeInfoAsync(request, null, ctx.Deadline, ctx.CancellationToken),
|
||||
// nameof(netmapServiceClient.LocalNodeInfoAsync));
|
||||
|
||||
Verifier.CheckResponse(response);
|
||||
|
||||
return response.Body.ToModel();
|
||||
|
|
|
@ -43,7 +43,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
|||
return response.Body.Header.Header.ToModel();
|
||||
}
|
||||
|
||||
internal async Task<ModelsV2.Object> GetObjectAsync(ContainerId cid, ObjectId oid, Context ctx)
|
||||
internal async Task<FrostFsObject> GetObjectAsync(ContainerId cid, ObjectId oid, Context ctx)
|
||||
{
|
||||
var sessionToken = await GetOrCreateSession(ctx);
|
||||
|
||||
|
@ -70,9 +70,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
|||
|
||||
request.Sign(Context.Key);
|
||||
|
||||
var obj = await GetObject(request, ctx);
|
||||
|
||||
return obj;
|
||||
return await GetObject(request, ctx);
|
||||
}
|
||||
|
||||
internal Task<ObjectId> PutObjectAsync(PutObjectParameters parameters, Context ctx)
|
||||
|
@ -89,7 +87,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
|||
return PutStreamObject(parameters, ctx);
|
||||
}
|
||||
|
||||
internal async Task<ObjectId> PutSingleObjectAsync(ModelsV2.Object modelObject, Context ctx)
|
||||
internal async Task<ObjectId> PutSingleObjectAsync(FrostFsObject modelObject, Context ctx)
|
||||
{
|
||||
var sessionToken = await GetOrCreateSession(ctx);
|
||||
|
||||
|
@ -178,7 +176,8 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
|||
|
||||
ObjectId? objectId;
|
||||
List<ObjectId> sentObjectIds = [];
|
||||
ModelsV2.Object? currentObject;
|
||||
|
||||
FrostFsObject? currentObject;
|
||||
|
||||
var networkSettings = await Context.Client.GetNetworkSettingsAsync(ctx);
|
||||
|
||||
|
@ -199,7 +198,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
|||
|
||||
largeObject.AppendBlock(buffer, bytesCount);
|
||||
|
||||
currentObject = new ModelsV2.Object(header.ContainerId, bytesCount < partSize ? buffer.Take(bytesCount).ToArray() : buffer)
|
||||
currentObject = new FrostFsObject(header.ContainerId, bytesCount < partSize ? buffer.Take(bytesCount).ToArray() : buffer)
|
||||
.SetSplit(split);
|
||||
|
||||
if (largeObject.PayloadLength == fullLength)
|
||||
|
@ -231,6 +230,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
|||
}
|
||||
|
||||
currentObject.AddAttributes(parameters.Header!.Attributes);
|
||||
|
||||
return await PutSingleObjectAsync(currentObject, ctx);
|
||||
}
|
||||
|
||||
|
@ -247,7 +247,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
|||
|
||||
var oid = new ObjectID { Value = hdr.Sha256() };
|
||||
|
||||
var request = new PutRequest
|
||||
var initRequest = new PutRequest
|
||||
{
|
||||
Body = new PutRequest.Types.Body
|
||||
{
|
||||
|
@ -258,8 +258,8 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
|||
}
|
||||
};
|
||||
|
||||
request.AddMetaHeader();
|
||||
request.AddObjectSessionToken(
|
||||
initRequest.AddMetaHeader();
|
||||
initRequest.AddObjectSessionToken(
|
||||
sessionToken,
|
||||
hdr.ContainerId,
|
||||
oid,
|
||||
|
@ -267,9 +267,10 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
|||
Context.Key
|
||||
);
|
||||
|
||||
request.Sign(Context.Key);
|
||||
initRequest.Sign(Context.Key);
|
||||
|
||||
using var stream = await PutObjectInit(request, ctx);
|
||||
using var stream = await PutObjectInit(initRequest, ctx);
|
||||
|
||||
var buffer = new byte[Constants.ObjectChunkSize];
|
||||
|
||||
while (true)
|
||||
|
@ -279,14 +280,17 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
|||
if (bufferLength == 0)
|
||||
break;
|
||||
|
||||
request.Body = new PutRequest.Types.Body
|
||||
var chunkRequest = new PutRequest(initRequest)
|
||||
{
|
||||
Chunk = ByteString.CopyFrom(buffer[..bufferLength]),
|
||||
Body = new PutRequest.Types.Body
|
||||
{
|
||||
Chunk = ByteString.CopyFrom(buffer[..bufferLength]),
|
||||
},
|
||||
VerifyHeader = null
|
||||
};
|
||||
|
||||
request.VerifyHeader = null;
|
||||
request.Sign(Context.Key);
|
||||
await stream.Write(request);
|
||||
chunkRequest.Sign(Context.Key);
|
||||
await stream.Write(chunkRequest);
|
||||
}
|
||||
|
||||
var response = await stream.Close();
|
||||
|
@ -295,7 +299,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
|||
return ObjectId.FromHash(response.Body.ObjectId.Value.ToByteArray());
|
||||
}
|
||||
|
||||
private async Task<ModelsV2.Object> GetObject(GetRequest request, Context ctx)
|
||||
private async Task<FrostFsObject> GetObject(GetRequest request, Context ctx)
|
||||
{
|
||||
var reader = GetObjectInit(request, ctx);
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ internal class ObjectTools(ClientEnvironment ctx) : ContextAccessor (ctx)
|
|||
return new ObjectID { Value = grpcHeader.Sha256() }.ToModel();
|
||||
}
|
||||
|
||||
internal Object.Object CreateObject(ModelsV2.Object @object)
|
||||
internal Object.Object CreateObject(FrostFsObject @object)
|
||||
{
|
||||
var grpcHeader = @object.Header.ToGrpcMessage();
|
||||
|
||||
|
@ -100,5 +100,4 @@ internal class ObjectTools(ClientEnvironment ctx) : ContextAccessor (ctx)
|
|||
Sum = ByteString.CopyFrom(data.Sha256())
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -1,4 +1,3 @@
|
|||
using FrostFS.SDK.ClientV2.Interfaces;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
using Grpc.Net.Client;
|
||||
using System;
|
||||
|
|
|
@ -7,31 +7,31 @@ namespace FrostFS.SDK.ClientV2.Extensions;
|
|||
|
||||
public static class ObjectExtensions
|
||||
{
|
||||
public static ModelsV2.Object SetPayloadLength(this ModelsV2.Object obj, ulong length)
|
||||
public static FrostFsObject SetPayloadLength(this FrostFsObject obj, ulong length)
|
||||
{
|
||||
obj.Header.PayloadLength = length;
|
||||
return obj;
|
||||
}
|
||||
|
||||
public static ModelsV2.Object AddAttribute(this ModelsV2.Object obj, string key, string value)
|
||||
public static FrostFsObject AddAttribute(this FrostFsObject obj, string key, string value)
|
||||
{
|
||||
obj.AddAttribute(new ObjectAttribute(key, value));
|
||||
return obj;
|
||||
}
|
||||
|
||||
public static ModelsV2.Object AddAttribute(this ModelsV2.Object obj, ObjectAttribute attribute)
|
||||
public static FrostFsObject AddAttribute(this FrostFsObject obj, ObjectAttribute attribute)
|
||||
{
|
||||
obj.Header.Attributes.Add(attribute);
|
||||
return obj;
|
||||
}
|
||||
|
||||
public static ModelsV2.Object AddAttributes(this ModelsV2.Object obj, IEnumerable<ObjectAttribute> attributes)
|
||||
public static FrostFsObject AddAttributes(this FrostFsObject obj, IEnumerable<ObjectAttribute> attributes)
|
||||
{
|
||||
obj.Header.Attributes.AddRange(attributes);
|
||||
return obj;
|
||||
}
|
||||
|
||||
public static ModelsV2.Object SetSplit(this ModelsV2.Object obj, Split split)
|
||||
public static FrostFsObject SetSplit(this FrostFsObject obj, Split split)
|
||||
{
|
||||
obj.Header.Split = split;
|
||||
return obj;
|
||||
|
@ -43,7 +43,7 @@ public static class ObjectExtensions
|
|||
return linkObject;
|
||||
}
|
||||
|
||||
public static ModelsV2.Object CalculateObjectId(this ModelsV2.Object obj)
|
||||
public static FrostFsObject CalculateObjectId(this FrostFsObject obj)
|
||||
{
|
||||
if (obj.Payload == null)
|
||||
throw new MissingFieldException("Payload cannot be null");
|
||||
|
|
|
@ -2,6 +2,7 @@ using System.Security.Cryptography;
|
|||
using FrostFS.Refs;
|
||||
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
using FrostFS.SDK.ProtosV2.Interfaces;
|
||||
using FrostFS.Session;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2;
|
||||
|
|
|
@ -12,6 +12,7 @@ using Org.BouncyCastle.Math;
|
|||
using FrostFS.Refs;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
using FrostFS.Session;
|
||||
using FrostFS.SDK.ProtosV2.Interfaces;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2;
|
||||
|
||||
|
@ -67,20 +68,21 @@ public static class RequestSigner
|
|||
{
|
||||
var hash = new byte[65];
|
||||
hash[0] = 0x04;
|
||||
key
|
||||
.SignHash(SHA512.Create().ComputeHash(data))
|
||||
.CopyTo(hash, 1);
|
||||
|
||||
key.SignHash(SHA512.Create().ComputeHash(data)).CopyTo(hash, 1);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
public static Signature SignMessagePart(this ECDsa key, IMessage? data)
|
||||
{
|
||||
var data2Sign = data is null ? Array.Empty<byte>() : data.ToByteArray();
|
||||
var data2Sign = data is null ? [] : data.ToByteArray();
|
||||
var sig = new Signature
|
||||
{
|
||||
Key = ByteString.CopyFrom(key.PublicKey()),
|
||||
Sign = ByteString.CopyFrom(key.SignData(data2Sign)),
|
||||
};
|
||||
|
||||
return sig;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ using FrostFS.Refs;
|
|||
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
using FrostFS.Session;
|
||||
using FrostFS.SDK.ProtosV2.Interfaces;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2;
|
||||
|
||||
|
|
|
@ -2,6 +2,6 @@ namespace FrostFS.SDK.ModelsV2;
|
|||
|
||||
public class CallStatistics
|
||||
{
|
||||
public string MethodName { get; set; }
|
||||
public string? MethodName { get; set; }
|
||||
public long ElapsedMicroSeconds { get; set; }
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
|
||||
using FrostFS.SDK.ModelsV2.Enums;
|
||||
using FrostFS.SDK.ModelsV2.Netmap;
|
||||
|
|
@ -8,7 +8,7 @@ namespace FrostFS.SDK.ClientV2;
|
|||
|
||||
public class Context()
|
||||
{
|
||||
private List<Interceptor> interceptors;
|
||||
private List<Interceptor>? interceptors;
|
||||
|
||||
public CancellationToken CancellationToken { get; set; } = default;
|
||||
public TimeSpan Timeout { get; set; } = default;
|
||||
|
@ -16,11 +16,11 @@ public class Context()
|
|||
|
||||
public DateTime? Deadline => Timeout.Ticks > 0 ? DateTime.UtcNow.Add(Timeout) : null;
|
||||
|
||||
public Action<CallStatistics> Callback { get; set; }
|
||||
public Action<CallStatistics>? Callback { get; set; }
|
||||
|
||||
public List<Interceptor> Interceptors
|
||||
{
|
||||
get { return interceptors ??= []; }
|
||||
set { interceptors = value; }
|
||||
get { return this.interceptors ??= []; }
|
||||
set { this.interceptors = value; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,16 +4,16 @@ using FrostFS.SDK.ModelsV2.Enums;
|
|||
|
||||
namespace FrostFS.SDK.ModelsV2;
|
||||
|
||||
public class Object
|
||||
public class FrostFsObject
|
||||
{
|
||||
public Object(ObjectId objectId, ObjectHeader header, byte[] payload)
|
||||
public FrostFsObject(ObjectId objectId, ObjectHeader header, byte[] payload)
|
||||
{
|
||||
ObjectId = objectId;
|
||||
Payload = payload;
|
||||
Header = header;
|
||||
}
|
||||
|
||||
public Object(ContainerId container, byte[] payload, ObjectType objectType = ObjectType.Regular)
|
||||
public FrostFsObject(ContainerId container, byte[] payload, ObjectType objectType = ObjectType.Regular)
|
||||
{
|
||||
Payload = payload;
|
||||
Header = new ObjectHeader(containerId: container, type: objectType, attributes: []);
|
||||
|
@ -41,7 +41,7 @@ public class Object
|
|||
}
|
||||
}
|
||||
|
||||
public class LargeObject(ContainerId container) : Object(container, [])
|
||||
public class LargeObject(ContainerId container) : FrostFsObject(container, [])
|
||||
{
|
||||
private readonly SHA256 payloadHash = SHA256.Create();
|
||||
|
||||
|
@ -64,7 +64,7 @@ public class LargeObject(ContainerId container) : Object(container, [])
|
|||
}
|
||||
}
|
||||
|
||||
public class LinkObject : Object
|
||||
public class LinkObject : FrostFsObject
|
||||
{
|
||||
public LinkObject(ContainerId containerId, SplitId splitId, LargeObject largeObject) : base (containerId, [])
|
||||
{
|
|
@ -1,35 +1,27 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
using FrostFS.SDK.ModelsV2.Enums;
|
||||
|
||||
namespace FrostFS.SDK.ModelsV2;
|
||||
|
||||
public class ObjectHeader
|
||||
public class ObjectHeader(
|
||||
ContainerId containerId,
|
||||
ObjectType type = ObjectType.Regular,
|
||||
params ObjectAttribute[] attributes
|
||||
)
|
||||
{
|
||||
public OwnerId? OwnerId { get; set; }
|
||||
|
||||
public List<ObjectAttribute> Attributes { get; set; }
|
||||
public List<ObjectAttribute> Attributes { get; set; } = [.. attributes];
|
||||
|
||||
public ContainerId ContainerId { get; set; }
|
||||
public ContainerId ContainerId { get; set; } = containerId;
|
||||
|
||||
public ulong PayloadLength { get; set; }
|
||||
|
||||
public byte[]? PayloadCheckSum { get; set; }
|
||||
|
||||
public ObjectType ObjectType { get; set; }
|
||||
public ObjectType ObjectType { get; set; } = type;
|
||||
|
||||
public Version? Version { get; set; }
|
||||
|
||||
public Split? Split { get; set; }
|
||||
|
||||
public ObjectHeader(
|
||||
ContainerId containerId,
|
||||
ObjectType type = ObjectType.Regular,
|
||||
params ObjectAttribute[] attributes
|
||||
)
|
||||
{
|
||||
Attributes = [.. attributes];
|
||||
ContainerId = containerId;
|
||||
ObjectType = type;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,21 +4,15 @@ using FrostFS.SDK.Cryptography;
|
|||
|
||||
namespace FrostFS.SDK.ModelsV2;
|
||||
|
||||
public class ObjectId
|
||||
public class ObjectId(string id)
|
||||
{
|
||||
public string Value { get; }
|
||||
|
||||
public ObjectId(string id)
|
||||
{
|
||||
Value = id;
|
||||
}
|
||||
public string Value { get; } = id;
|
||||
|
||||
public static ObjectId FromHash(byte[] hash)
|
||||
{
|
||||
if (hash.Length != Constants.Sha256HashLength)
|
||||
{
|
||||
throw new FormatException("ObjectID must be a sha256 hash.");
|
||||
}
|
||||
|
||||
return new ObjectId(Base58.Encode(hash));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
namespace FrostFS.Session;
|
||||
using FrostFS.Session;
|
||||
|
||||
namespace FrostFS.SDK.ProtosV2.Interfaces;
|
||||
|
||||
public interface IRequest : IVerifiableMessage
|
||||
{
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using Google.Protobuf;
|
||||
|
||||
using FrostFS.Session;
|
||||
using FrostFS.SDK.ProtosV2.Interfaces;
|
||||
|
||||
namespace FrostFS.Container;
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using FrostFS.Session;
|
||||
using FrostFS.SDK.ProtosV2.Interfaces;
|
||||
using FrostFS.Session;
|
||||
using Google.Protobuf;
|
||||
|
||||
namespace FrostFS.Netmap;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Diagnostics;
|
||||
using FrostFS.SDK.ProtosV2.Interfaces;
|
||||
using FrostFS.Session;
|
||||
using Google.Protobuf;
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Google.Protobuf;
|
||||
using FrostFS.SDK.ProtosV2.Interfaces;
|
||||
using Google.Protobuf;
|
||||
|
||||
namespace FrostFS.Session;
|
||||
|
||||
|
|
|
@ -1,118 +1,112 @@
|
|||
using FrostFS.SDK.ClientV2;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
using FrostFS.SDK.ModelsV2.Enums;
|
||||
using FrostFS.SDK.ModelsV2.Netmap;
|
||||
using FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap;
|
||||
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
using FrostFS.SDK.ModelsV2.Netmap;
|
||||
using FrostFS.SDK.ModelsV2.Enums;
|
||||
using Google.Protobuf;
|
||||
using FrostFS.SDK.ClientV2.Interfaces;
|
||||
|
||||
namespace FrostFS.SDK.Tests;
|
||||
|
||||
public class ContainerTest
|
||||
{
|
||||
private readonly string key = "KwHDAJ66o8FoLBjVbjP2sWBmgBMGjt7Vv4boA7xQrBoAYBE397Aq";
|
||||
|
||||
[Fact]
|
||||
public async void CreateContainerTest()
|
||||
public abstract class ContainerTestsBase
|
||||
{
|
||||
protected readonly string key = "KwHDAJ66o8FoLBjVbjP2sWBmgBMGjt7Vv4boA7xQrBoAYBE397Aq";
|
||||
|
||||
protected IOptions<ClientSettings> Settings { get; set; }
|
||||
protected ContainerMocker Mocker { get; set; }
|
||||
|
||||
protected ContainerTestsBase()
|
||||
{
|
||||
var factory = new PutContainerMockFactory(this.key)
|
||||
Settings = Options.Create(new ClientSettings
|
||||
{
|
||||
Key = key,
|
||||
Host = "http://localhost:8080"
|
||||
});
|
||||
|
||||
Mocker = new ContainerMocker(this.key)
|
||||
{
|
||||
PlacementPolicy = new PlacementPolicy(true, new Replica(1)),
|
||||
Version = new ModelsV2.Version(2, 13),
|
||||
ContainerGuid = Guid.NewGuid()
|
||||
};
|
||||
}
|
||||
|
||||
var settings = Options.Create(new ClientSettings
|
||||
{
|
||||
Key = key,
|
||||
Host = "http://localhost:8080"
|
||||
});
|
||||
protected IFrostFSClient GetClient()
|
||||
{
|
||||
return ClientV2.Client.GetTestInstance(
|
||||
Settings,
|
||||
null,
|
||||
new NetworkMocker(this.key).GetMock().Object,
|
||||
new SessionMocker(this.key).GetMock().Object,
|
||||
Mocker.GetMock().Object,
|
||||
new ObjectMocker(this.key).GetMock().Object);
|
||||
}
|
||||
}
|
||||
|
||||
var fsClient = Client.GetTestInstance(
|
||||
settings,
|
||||
null,
|
||||
new NetmapMockFactory(this.key).GetMock().Object,
|
||||
new SessionMockFactory(this.key).GetMock().Object,
|
||||
factory.GetMock().Object,
|
||||
new ObjectMockFactory(this.key).GetMock().Object);
|
||||
|
||||
var result = await fsClient.CreateContainerAsync(new ModelsV2.Container(BasicAcl.PublicRW, factory.PlacementPolicy));
|
||||
public class ContainerTest : ContainerTestsBase
|
||||
{
|
||||
[Fact]
|
||||
public async void CreateContainerTest()
|
||||
{
|
||||
var result = await GetClient().CreateContainerAsync(new ModelsV2.Container(BasicAcl.PublicRW, Mocker.PlacementPolicy));
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.NotNull(result.Value);
|
||||
Assert.True(Base58.Encode(factory.ContainerGuid.ToBytes()) == result.Value);
|
||||
Assert.True(Base58.Encode(Mocker.ContainerGuid.ToBytes()) == result.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void GetContainerTest()
|
||||
{
|
||||
var factory = new GetContainerMockFactory(this.key)
|
||||
{
|
||||
PlacementPolicy = new PlacementPolicy(true, new Replica(1)),
|
||||
Version = new ModelsV2.Version(2, 13),
|
||||
Acl = BasicAcl.PublicRO,
|
||||
ContainerGuid = Guid.NewGuid(),
|
||||
};
|
||||
var cid = new ContainerId(Base58.Encode(Mocker.ContainerGuid.ToBytes()));
|
||||
|
||||
var settings = Options.Create(new ClientSettings
|
||||
{
|
||||
Key = key,
|
||||
Host = "http://localhost:8080"
|
||||
});
|
||||
Mocker.Acl = BasicAcl.PublicRO;
|
||||
|
||||
var fsClient = Client.GetTestInstance(
|
||||
settings,
|
||||
null,
|
||||
new NetmapMockFactory(this.key).GetMock().Object,
|
||||
new SessionMockFactory(this.key).GetMock().Object,
|
||||
factory.GetMock().Object,
|
||||
new ObjectMockFactory(this.key).GetMock().Object);
|
||||
|
||||
var cid = new ContainerId(Base58.Encode(factory.ContainerGuid.ToBytes()));
|
||||
|
||||
var context = new Context();
|
||||
|
||||
var result = await fsClient.GetContainerAsync(cid, context);
|
||||
var result = await GetClient().GetContainerAsync(cid);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(factory.Acl, result.BasicAcl);
|
||||
Assert.Equal(factory.ContainerGuid, result.Nonce);
|
||||
Assert.Equal(0, factory.PlacementPolicy.CompareTo(result.PlacementPolicy));
|
||||
Assert.Equal(factory.Version.ToString(), result.Version!.ToString());
|
||||
Assert.Equal(Mocker.Acl, result.BasicAcl);
|
||||
Assert.Equal(Mocker.ContainerGuid, result.Nonce);
|
||||
Assert.Equal(0, Mocker.PlacementPolicy.CompareTo(result.PlacementPolicy));
|
||||
Assert.Equal(Mocker.Version.ToString(), result.Version!.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void GetContainerListTest()
|
||||
{
|
||||
Mocker.ContainerIds.Add([0xaa]);
|
||||
Mocker.ContainerIds.Add([0xbb]);
|
||||
Mocker.ContainerIds.Add([0xcc]);
|
||||
|
||||
var result = GetClient().ListContainersAsync();
|
||||
|
||||
Assert.NotNull(result);
|
||||
|
||||
int i = 0;
|
||||
await foreach (var cid in result)
|
||||
{
|
||||
var val = Base58.Encode(ByteString.CopyFrom(Mocker.ContainerIds[i++]).ToByteArray());
|
||||
Assert.Equal(val, cid.Value);
|
||||
}
|
||||
|
||||
Assert.Equal(3, i);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void DeleteContainerAsyncTest()
|
||||
{
|
||||
var factory = new DeleteContainerMockFactory(this.key)
|
||||
{
|
||||
Version = new ModelsV2.Version(2, 13),
|
||||
Acl = BasicAcl.PublicRW,
|
||||
ContainerGuid = Guid.NewGuid(),
|
||||
};
|
||||
var cid = new ContainerId(Base58.Encode(Mocker.ContainerGuid.ToBytes()));
|
||||
|
||||
var settings = Options.Create(new ClientSettings
|
||||
{
|
||||
Key = key,
|
||||
Host = "http://localhost:8080"
|
||||
});
|
||||
await GetClient().DeleteContainerAsync(cid);
|
||||
|
||||
var fsClient = Client.GetTestInstance(
|
||||
settings,
|
||||
null,
|
||||
new NetmapMockFactory(this.key).GetMock().Object,
|
||||
new SessionMockFactory(this.key).GetMock().Object,
|
||||
factory.GetMock().Object,
|
||||
new ObjectMockFactory(this.key).GetMock().Object);
|
||||
Assert.Single(Mocker.Requests);
|
||||
|
||||
var cid = new ContainerId(Base58.Encode(factory.ContainerGuid.ToBytes()));
|
||||
|
||||
await fsClient.DeleteContainerAsync(cid);
|
||||
|
||||
Assert.Single(factory.Requests);
|
||||
|
||||
var request = factory.Requests.First();
|
||||
var request = Mocker.Requests.First();
|
||||
|
||||
Assert.Equal(cid.ToGrpcMessage(), request.Request.Body.ContainerId);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,10 @@
|
|||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="TestData\cat.jpeg" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
|
@ -25,4 +29,10 @@
|
|||
<ProjectReference Include="..\FrostFS.SDK.ClientV2\FrostFS.SDK.ClientV2.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="TestData\cat.jpg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
60
src/FrostFS.SDK.Tests/Mocks/AsyncStreamReaderMock.cs
Normal file
60
src/FrostFS.SDK.Tests/Mocks/AsyncStreamReaderMock.cs
Normal file
|
@ -0,0 +1,60 @@
|
|||
using FrostFS.Object;
|
||||
using FrostFS.Session;
|
||||
using Google.Protobuf;
|
||||
using Grpc.Core;
|
||||
using FrostFS.SDK.ClientV2;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
using FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap;
|
||||
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace FrostFS.SDK.Tests;
|
||||
|
||||
public class AsyncStreamReaderMock(string key, ObjectHeader objectHeader) : ServiceBase(key), IAsyncStreamReader<GetResponse>
|
||||
{
|
||||
public GetResponse Current
|
||||
{
|
||||
get
|
||||
{
|
||||
var header = new Header
|
||||
{
|
||||
ContainerId = objectHeader.ContainerId.ToGrpcMessage(),
|
||||
PayloadLength = objectHeader.PayloadLength,
|
||||
Version = objectHeader.Version!.ToGrpcMessage(),
|
||||
OwnerId = objectHeader.OwnerId!.ToGrpcMessage()
|
||||
};
|
||||
|
||||
foreach (var attr in objectHeader.Attributes)
|
||||
header.Attributes.Add(attr.ToGrpcMessage());
|
||||
|
||||
var response = new GetResponse
|
||||
{
|
||||
Body = new GetResponse.Types.Body
|
||||
{
|
||||
Init = new GetResponse.Types.Body.Types.Init
|
||||
{
|
||||
Header = header,
|
||||
ObjectId = new Refs.ObjectID { Value = ByteString.CopyFrom(SHA256.HashData(Array.Empty<byte>())) },
|
||||
Signature = new Refs.Signature
|
||||
{
|
||||
Key = ByteString.CopyFrom(Key.PublicKey()),
|
||||
Sign = ByteString.CopyFrom(Key.SignData(header.ToByteArray())),
|
||||
}
|
||||
}
|
||||
},
|
||||
MetaHeader = new ResponseMetaHeader()
|
||||
};
|
||||
|
||||
response.VerifyHeader = GetResponseVerificationHeader(response);
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
public Task<bool> MoveNext(CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
}
|
||||
|
29
src/FrostFS.SDK.Tests/Mocks/ClientStreamWriter.cs
Normal file
29
src/FrostFS.SDK.Tests/Mocks/ClientStreamWriter.cs
Normal file
|
@ -0,0 +1,29 @@
|
|||
using Grpc.Core;
|
||||
using FrostFS.SDK.ProtosV2.Interfaces;
|
||||
|
||||
namespace FrostFS.SDK.Tests;
|
||||
|
||||
public class ClientStreamWriter : IClientStreamWriter<IRequest>
|
||||
{
|
||||
public List<IRequest> Messages { get; set; } = [];
|
||||
public bool CompletedTask { get; private set; }
|
||||
|
||||
public WriteOptions? WriteOptions
|
||||
{
|
||||
get => throw new NotImplementedException();
|
||||
set => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task CompleteAsync()
|
||||
{
|
||||
CompletedTask = true;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task WriteAsync(IRequest message)
|
||||
{
|
||||
Messages.Add(message);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
|
@ -17,6 +17,7 @@ namespace FrostFS.SDK.Tests;
|
|||
|
||||
public abstract class ServiceBase(string key)
|
||||
{
|
||||
public string StringKey { get; private set; } = key;
|
||||
public ECDsa Key { get; private set; } = key.LoadWif();
|
||||
public ModelsV2.Version Version { get; set; } = DefaultVersion;
|
||||
public BasicAcl Acl { get; set; } = DefaultAcl;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using FrostFS.Container;
|
||||
using Moq;
|
||||
|
||||
|
||||
namespace FrostFS.SDK.Tests;
|
||||
|
||||
public class ContainerStub(string key) : ContainerServiceBase(key)
|
|
@ -1,54 +0,0 @@
|
|||
using FrostFS.Container;
|
||||
using FrostFS.Session;
|
||||
using Grpc.Core;
|
||||
using Moq;
|
||||
|
||||
namespace FrostFS.SDK.Tests;
|
||||
|
||||
public class DeleteContainerMockFactory(string key) : ContainerServiceBase(key)
|
||||
{
|
||||
public override Mock<ContainerService.ContainerServiceClient> GetMock()
|
||||
{
|
||||
var mock = new Mock<ContainerService.ContainerServiceClient>();
|
||||
|
||||
var v = mock.Setup(x => x.DeleteAsync(
|
||||
It.IsAny<DeleteRequest>(),
|
||||
It.IsAny<Metadata>(),
|
||||
It.IsAny<DateTime?>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.Returns((DeleteRequest r, Metadata m, DateTime? dt, CancellationToken ct) =>
|
||||
{
|
||||
Requests.Add(new RequestData<DeleteRequest>(r, m, dt, ct));
|
||||
|
||||
var response = new DeleteResponse
|
||||
{
|
||||
Body = new DeleteResponse.Types.Body(),
|
||||
MetaHeader = new ResponseMetaHeader()
|
||||
};
|
||||
|
||||
var metadata = new Metadata();
|
||||
|
||||
response.VerifyHeader = GetResponseVerificationHeader(response);
|
||||
|
||||
return new AsyncUnaryCall<DeleteResponse>(
|
||||
Task.FromResult(response),
|
||||
Task.FromResult(metadata),
|
||||
() => new Grpc.Core.Status(StatusCode.OK, string.Empty),
|
||||
() => metadata,
|
||||
() => { });
|
||||
});
|
||||
|
||||
return mock;
|
||||
}
|
||||
|
||||
public List<RequestData<DeleteRequest>> Requests = [];
|
||||
}
|
||||
|
||||
public class RequestData<T>(T request, Metadata m, DateTime? dt, CancellationToken ct)
|
||||
{
|
||||
public T Request => request;
|
||||
public Metadata Metadata => m;
|
||||
public DateTime? deadline => dt;
|
||||
public CancellationToken CancellationToken => ct;
|
||||
}
|
||||
|
|
@ -8,10 +8,13 @@ using FrostFS.SDK.ClientV2;
|
|||
using FrostFS.SDK.ModelsV2.Netmap;
|
||||
using FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap;
|
||||
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||
using FrostFS.Session;
|
||||
using FrostFS.Refs;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FrostFS.SDK.Tests;
|
||||
|
||||
public class GetContainerMockFactory(string key) : ContainerServiceBase(key)
|
||||
public class ContainerMocker(string key) : ContainerServiceBase(key)
|
||||
{
|
||||
public override Mock<ContainerService.ContainerServiceClient> GetMock()
|
||||
{
|
||||
|
@ -19,7 +22,46 @@ public class GetContainerMockFactory(string key) : ContainerServiceBase(key)
|
|||
|
||||
var grpcVersion = Version.ToGrpcMessage();
|
||||
|
||||
var response = new GetResponse
|
||||
PutResponse putResponse = new()
|
||||
{
|
||||
Body = new PutResponse.Types.Body
|
||||
{
|
||||
ContainerId = new ContainerID
|
||||
{
|
||||
Value = ByteString.CopyFrom(ContainerGuid.ToBytes())
|
||||
}
|
||||
},
|
||||
MetaHeader = new ResponseMetaHeader
|
||||
{
|
||||
Version = Version is null ? DefaultVersion.ToGrpcMessage() : Version.ToGrpcMessage(),
|
||||
Epoch = 100,
|
||||
Ttl = 1
|
||||
}
|
||||
};
|
||||
|
||||
putResponse.VerifyHeader = GetResponseVerificationHeader(putResponse);
|
||||
|
||||
var metadata = new Metadata();
|
||||
var putContainerResponse = new AsyncUnaryCall<PutResponse>(
|
||||
Task.FromResult(putResponse),
|
||||
Task.FromResult(metadata),
|
||||
() => new Grpc.Core.Status(StatusCode.OK, string.Empty),
|
||||
() => metadata,
|
||||
() => { });
|
||||
|
||||
mock.Setup(x => x.PutAsync(
|
||||
It.IsAny<PutRequest>(),
|
||||
It.IsAny<Metadata>(),
|
||||
It.IsAny<DateTime?>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.Returns((PutRequest r, Metadata m, DateTime? dt, CancellationToken ct) =>
|
||||
{
|
||||
Verifier.CheckRequest(r);
|
||||
|
||||
return putContainerResponse;
|
||||
});
|
||||
|
||||
var getResponse = new GetResponse
|
||||
{
|
||||
Body = new GetResponse.Types.Body
|
||||
{
|
||||
|
@ -34,7 +76,7 @@ public class GetContainerMockFactory(string key) : ContainerServiceBase(key)
|
|||
MetaHeader = ResponseMetaHeader
|
||||
};
|
||||
|
||||
response.VerifyHeader = GetResponseVerificationHeader(response);
|
||||
getResponse.VerifyHeader = GetResponseVerificationHeader(getResponse);
|
||||
|
||||
mock.Setup(x => x.GetAsync(
|
||||
It.IsAny<GetRequest>(),
|
||||
|
@ -46,13 +88,74 @@ public class GetContainerMockFactory(string key) : ContainerServiceBase(key)
|
|||
Verifier.CheckRequest(r);
|
||||
|
||||
return new AsyncUnaryCall<GetResponse>(
|
||||
Task.FromResult(response),
|
||||
Task.FromResult(getResponse),
|
||||
Task.FromResult(ResponseMetaData),
|
||||
() => new Grpc.Core.Status(StatusCode.OK, string.Empty),
|
||||
() => ResponseMetaData,
|
||||
() => { });
|
||||
});
|
||||
|
||||
var listResponse = new ListResponse
|
||||
{
|
||||
Body = new ListResponse.Types.Body(),
|
||||
MetaHeader = ResponseMetaHeader
|
||||
};
|
||||
|
||||
foreach (var item in ContainerIds)
|
||||
{
|
||||
listResponse.Body.ContainerIds.Add(new ContainerID { Value = ByteString.CopyFrom(item) });
|
||||
}
|
||||
|
||||
listResponse.VerifyHeader = GetResponseVerificationHeader(listResponse);
|
||||
|
||||
mock.Setup(x => x.ListAsync(
|
||||
It.IsAny<ListRequest>(),
|
||||
It.IsAny<Metadata>(),
|
||||
It.IsAny<DateTime?>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.Returns((ListRequest r, Metadata m, DateTime? dt, CancellationToken ct) =>
|
||||
{
|
||||
Verifier.CheckRequest(r);
|
||||
|
||||
return new AsyncUnaryCall<ListResponse>(
|
||||
Task.FromResult(listResponse),
|
||||
Task.FromResult(ResponseMetaData),
|
||||
() => new Grpc.Core.Status(StatusCode.OK, string.Empty),
|
||||
() => ResponseMetaData,
|
||||
() => { });
|
||||
});
|
||||
|
||||
var v = mock.Setup(x => x.DeleteAsync(
|
||||
It.IsAny<DeleteRequest>(),
|
||||
It.IsAny<Metadata>(),
|
||||
It.IsAny<DateTime?>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.Returns((DeleteRequest r, Metadata m, DateTime? dt, CancellationToken ct) =>
|
||||
{
|
||||
Requests.Add(new RequestData<DeleteRequest>(r, m, dt, ct));
|
||||
|
||||
var response = new DeleteResponse
|
||||
{
|
||||
Body = new DeleteResponse.Types.Body(),
|
||||
MetaHeader = new ResponseMetaHeader()
|
||||
};
|
||||
|
||||
var metadata = new Metadata();
|
||||
|
||||
response.VerifyHeader = GetResponseVerificationHeader(response);
|
||||
|
||||
return new AsyncUnaryCall<DeleteResponse>(
|
||||
Task.FromResult(response),
|
||||
Task.FromResult(metadata),
|
||||
() => new Grpc.Core.Status(StatusCode.OK, string.Empty),
|
||||
() => metadata,
|
||||
() => { });
|
||||
});
|
||||
|
||||
return mock;
|
||||
}
|
||||
|
||||
public List<byte[]> ContainerIds { get; set; } = [];
|
||||
|
||||
public List<RequestData<DeleteRequest>> Requests { get; set; } = [];
|
||||
}
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
using FrostFS.Container;
|
||||
using FrostFS.Session;
|
||||
using Google.Protobuf;
|
||||
using Grpc.Core;
|
||||
using Moq;
|
||||
using FrostFS.SDK.ClientV2;
|
||||
using FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap;
|
||||
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
using FrostFS.Refs;
|
||||
|
||||
namespace FrostFS.SDK.Tests;
|
||||
|
||||
public class PutContainerMockFactory(string key) : ContainerServiceBase(key)
|
||||
{
|
||||
public override Mock<ContainerService.ContainerServiceClient> GetMock()
|
||||
{
|
||||
var mock = new Mock<ContainerService.ContainerServiceClient>();
|
||||
|
||||
PutResponse response = new()
|
||||
{
|
||||
Body = new PutResponse.Types.Body
|
||||
{
|
||||
ContainerId = new ContainerID
|
||||
{
|
||||
Value = ByteString.CopyFrom(ContainerGuid.ToBytes())
|
||||
}
|
||||
},
|
||||
MetaHeader = new ResponseMetaHeader
|
||||
{
|
||||
Version = Version is null ? DefaultVersion.ToGrpcMessage() : Version.ToGrpcMessage(),
|
||||
Epoch = 100,
|
||||
Ttl = 1
|
||||
}
|
||||
};
|
||||
|
||||
response.VerifyHeader = PutResponseVerificationHeader(response);
|
||||
|
||||
var metadata = new Metadata();
|
||||
var putContainerResponse = new AsyncUnaryCall<PutResponse>(
|
||||
Task.FromResult(response),
|
||||
Task.FromResult(metadata),
|
||||
() => new Grpc.Core.Status(StatusCode.OK, string.Empty),
|
||||
() => metadata,
|
||||
() => { });
|
||||
|
||||
mock.Setup(x => x.PutAsync(
|
||||
It.IsAny<PutRequest>(),
|
||||
It.IsAny<Metadata>(),
|
||||
It.IsAny<DateTime?>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.Returns((PutRequest r, Metadata m, DateTime? dt, CancellationToken ct) =>
|
||||
{
|
||||
Verifier.CheckRequest(r);
|
||||
|
||||
return putContainerResponse;
|
||||
});
|
||||
|
||||
return mock;
|
||||
}
|
||||
|
||||
private ResponseVerificationHeader PutResponseVerificationHeader(PutResponse response)
|
||||
{
|
||||
var verifyHeader = new ResponseVerificationHeader
|
||||
{
|
||||
MetaSignature = new Signature
|
||||
{
|
||||
Key = ByteString.CopyFrom(Key.PublicKey()),
|
||||
Scheme = SignatureScheme.EcdsaRfc6979Sha256,
|
||||
Sign = ByteString.CopyFrom(Key.SignData(response.MetaHeader.ToByteArray()))
|
||||
},
|
||||
BodySignature = new Signature
|
||||
{
|
||||
Key = ByteString.CopyFrom(Key.PublicKey()),
|
||||
Scheme = SignatureScheme.EcdsaRfc6979Sha256,
|
||||
Sign = ByteString.CopyFrom(Key.SignData(response.GetBody().ToByteArray()))
|
||||
},
|
||||
OriginSignature = new Signature
|
||||
{
|
||||
Key = ByteString.CopyFrom(Key.PublicKey()),
|
||||
Scheme = SignatureScheme.EcdsaRfc6979Sha256,
|
||||
Sign = ByteString.CopyFrom(Key.SignData([]))
|
||||
}
|
||||
};
|
||||
|
||||
return verifyHeader;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using Grpc.Core;
|
||||
|
||||
namespace FrostFS.SDK.Tests;
|
||||
|
||||
public class RequestData<T>(T request, Metadata m, DateTime? dt, CancellationToken ct)
|
||||
{
|
||||
public T Request => request;
|
||||
public Metadata Metadata => m;
|
||||
public DateTime? Deadline => dt;
|
||||
public CancellationToken CancellationToken => ct;
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
using Moq;
|
||||
using FrostFS.Netmap;
|
||||
|
||||
namespace FrostFS.SDK.Tests;
|
||||
|
||||
public class NetmapMockFactory(string key) : ServiceBase(key)
|
||||
{
|
||||
public Mock<NetmapService.NetmapServiceClient> GetMock()
|
||||
{
|
||||
var mock = new Mock<NetmapService.NetmapServiceClient>();
|
||||
|
||||
return mock;
|
||||
}
|
||||
}
|
78
src/FrostFS.SDK.Tests/Mocks/NetworkMocker.cs
Normal file
78
src/FrostFS.SDK.Tests/Mocks/NetworkMocker.cs
Normal file
|
@ -0,0 +1,78 @@
|
|||
using Moq;
|
||||
using FrostFS.Netmap;
|
||||
using Grpc.Core;
|
||||
using FrostFS.SDK.ClientV2;
|
||||
using Google.Protobuf;
|
||||
using NuGet.Frameworks;
|
||||
|
||||
namespace FrostFS.SDK.Tests;
|
||||
|
||||
public class NetworkMocker(string key) : ServiceBase(key)
|
||||
{
|
||||
private static readonly string[] parameterKeys = [
|
||||
"ContainerFee",
|
||||
"EpochDuration",
|
||||
"IRCandidateFee",
|
||||
"MaxECDataCount",
|
||||
"MaxECParityCount",
|
||||
"MaxObjectSize",
|
||||
"WithdrawalFee",
|
||||
"HomomorphicHashingDisabled",
|
||||
"MaintenanceModeAllowed" ];
|
||||
|
||||
public Dictionary<string, byte[]>? Parameters { get; set; }
|
||||
|
||||
public Mock<NetmapService.NetmapServiceClient> GetMock()
|
||||
{
|
||||
var mock = new Mock<NetmapService.NetmapServiceClient>();
|
||||
|
||||
var networkInfoResponse = new NetworkInfoResponse();
|
||||
|
||||
var networkConfig = new NetworkConfig();
|
||||
|
||||
foreach (var key in parameterKeys)
|
||||
{
|
||||
networkConfig.Parameters.Add(new NetworkConfig.Types.Parameter
|
||||
{
|
||||
Key = ByteString.CopyFromUtf8(key),
|
||||
Value = (Parameters != null && Parameters.TryGetValue(key, out byte[]? value)) ? ByteString.CopyFrom(value) : ByteString.CopyFrom(0)
|
||||
});
|
||||
}
|
||||
|
||||
var response = new NetworkInfoResponse
|
||||
{
|
||||
Body = new NetworkInfoResponse.Types.Body
|
||||
{
|
||||
NetworkInfo = new NetworkInfo
|
||||
{
|
||||
CurrentEpoch = 99,
|
||||
MagicNumber = 13,
|
||||
MsPerBlock = 999,
|
||||
NetworkConfig = networkConfig
|
||||
}
|
||||
},
|
||||
MetaHeader = ResponseMetaHeader
|
||||
};
|
||||
|
||||
response.VerifyHeader = GetResponseVerificationHeader(response);
|
||||
|
||||
mock.Setup(x => x.NetworkInfoAsync(
|
||||
It.IsAny<NetworkInfoRequest>(),
|
||||
It.IsAny<Metadata>(),
|
||||
It.IsAny<DateTime?>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.Returns((NetworkInfoRequest r, Metadata m, DateTime? dt, CancellationToken ct) =>
|
||||
{
|
||||
Verifier.CheckRequest(r);
|
||||
|
||||
return new AsyncUnaryCall<NetworkInfoResponse>(
|
||||
Task.FromResult(response),
|
||||
Task.FromResult(ResponseMetaData),
|
||||
() => new Grpc.Core.Status(StatusCode.OK, string.Empty),
|
||||
() => ResponseMetaData,
|
||||
() => { });
|
||||
});
|
||||
|
||||
return mock;
|
||||
}
|
||||
}
|
|
@ -1,101 +1,208 @@
|
|||
using Moq;
|
||||
using FrostFS.Object;
|
||||
using Grpc.Core;
|
||||
using FrostFS.SDK.ClientV2;
|
||||
using FrostFS.Session;
|
||||
using Google.Protobuf;
|
||||
using Grpc.Core;
|
||||
using Moq;
|
||||
using FrostFS.SDK.ClientV2;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
using FrostFS.Object;
|
||||
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||
using System.Security.Cryptography;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
|
||||
namespace FrostFS.SDK.Tests;
|
||||
|
||||
public class ObjectMockFactory(string key) : ObjectServiceBase(key)
|
||||
public class ObjectMocker(string key) : ObjectServiceBase(key)
|
||||
{
|
||||
public override Mock<ObjectService.ObjectServiceClient> GetMock()
|
||||
{
|
||||
var mock = new Mock<ObjectService.ObjectServiceClient>();
|
||||
|
||||
GetResponse response = new()
|
||||
if (ObjectHeader != null)
|
||||
{
|
||||
Body = new GetResponse.Types.Body
|
||||
{
|
||||
},
|
||||
MetaHeader = ResponseMetaHeader
|
||||
};
|
||||
|
||||
response.VerifyHeader = GetResponseVerificationHeader(response);
|
||||
|
||||
mock.Setup(x => x.Get(
|
||||
It.IsAny<GetRequest>(),
|
||||
It.IsAny<Metadata>(),
|
||||
It.IsAny<DateTime?>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.Returns((GetRequest r, Metadata m, DateTime? dt, CancellationToken ct) =>
|
||||
mock.Setup(x => x.Get(
|
||||
It.IsAny<GetRequest>(),
|
||||
It.IsAny<Metadata>(),
|
||||
It.IsAny<DateTime?>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.Returns((GetRequest r, Metadata m, DateTime? dt, CancellationToken ct) =>
|
||||
{
|
||||
Verifier.CheckRequest(r);
|
||||
|
||||
return new AsyncServerStreamingCall<GetResponse>(
|
||||
new AsyncStreamReaderMock(key, ObjectHeader),
|
||||
return new AsyncServerStreamingCall<GetResponse>(
|
||||
new AsyncStreamReaderMock(StringKey, ObjectHeader),
|
||||
Task.FromResult(ResponseMetaData),
|
||||
() => new Grpc.Core.Status(StatusCode.OK, string.Empty),
|
||||
() => ResponseMetaData,
|
||||
() => { });
|
||||
});
|
||||
|
||||
HeadResponse ??= new Header
|
||||
{
|
||||
CreationEpoch = 99,
|
||||
ContainerId = ObjectHeader.ContainerId.ToGrpcMessage(),
|
||||
ObjectType = ObjectType.Regular,
|
||||
OwnerId = ObjectHeader.OwnerId!.ToGrpcMessage(),
|
||||
PayloadLength = 1,
|
||||
PayloadHash = new Refs.Checksum { Type = Refs.ChecksumType.Sha256, Sum = ByteString.CopyFrom(SHA256.HashData([0xff])) },
|
||||
Version = ObjectHeader.Version!.ToGrpcMessage()
|
||||
};
|
||||
|
||||
HeadResponse headResponse = new()
|
||||
{
|
||||
Body = new HeadResponse.Types.Body
|
||||
{
|
||||
Header = new HeaderWithSignature
|
||||
{
|
||||
Header = HeadResponse
|
||||
}
|
||||
},
|
||||
MetaHeader = ResponseMetaHeader
|
||||
};
|
||||
|
||||
headResponse.Body.Header.Header.Attributes.Add(new Header.Types.Attribute { Key = "k", Value = "v" });
|
||||
|
||||
headResponse.Body.Header.Signature = new Refs.Signature
|
||||
{
|
||||
Key = ByteString.CopyFrom(Key.PublicKey()),
|
||||
Sign = ByteString.CopyFrom(Key.SignData(headResponse.Body.Header.ToByteArray())),
|
||||
};
|
||||
|
||||
headResponse.VerifyHeader = GetResponseVerificationHeader(headResponse);
|
||||
|
||||
mock.Setup(x => x.HeadAsync(
|
||||
It.IsAny<HeadRequest>(),
|
||||
It.IsAny<Metadata>(),
|
||||
It.IsAny<DateTime?>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.Returns((HeadRequest r, Metadata m, DateTime? dt, CancellationToken ct) =>
|
||||
{
|
||||
Verifier.CheckRequest(r);
|
||||
|
||||
HeadRequests.Add(r);
|
||||
|
||||
return new AsyncUnaryCall<HeadResponse>(
|
||||
Task.FromResult(headResponse),
|
||||
Task.FromResult(ResponseMetaData),
|
||||
() => new Grpc.Core.Status(StatusCode.OK, string.Empty),
|
||||
() => ResponseMetaData,
|
||||
() => { });
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
if (ResultObjectId != null)
|
||||
{
|
||||
PutResponse putResponse = new()
|
||||
{
|
||||
Body = new PutResponse.Types.Body
|
||||
{
|
||||
ObjectId = new Refs.ObjectID
|
||||
{
|
||||
Value = ByteString.CopyFrom(ResultObjectId)
|
||||
}
|
||||
},
|
||||
MetaHeader = ResponseMetaHeader,
|
||||
};
|
||||
|
||||
putResponse.VerifyHeader = GetResponseVerificationHeader(putResponse);
|
||||
|
||||
mock.Setup(x => x.Put(
|
||||
It.IsAny<Metadata>(),
|
||||
It.IsAny<DateTime?>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.Returns((Metadata m, DateTime? dt, CancellationToken ct) =>
|
||||
{
|
||||
return new AsyncClientStreamingCall<PutRequest, PutResponse>(
|
||||
ClientStreamWriter!,
|
||||
Task.FromResult(putResponse),
|
||||
Task.FromResult(ResponseMetaData),
|
||||
() => new Grpc.Core.Status(StatusCode.OK, string.Empty),
|
||||
() => ResponseMetaData,
|
||||
() => { });
|
||||
});
|
||||
}
|
||||
|
||||
PutSingleResponse putSingleResponse = new()
|
||||
{
|
||||
Body = new PutSingleResponse.Types.Body(),
|
||||
MetaHeader = ResponseMetaHeader,
|
||||
};
|
||||
|
||||
putSingleResponse.VerifyHeader = GetResponseVerificationHeader(putSingleResponse);
|
||||
|
||||
mock.Setup(x => x.PutSingleAsync(
|
||||
It.IsAny<PutSingleRequest>(),
|
||||
It.IsAny<Metadata>(),
|
||||
It.IsAny<DateTime?>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.Returns((PutSingleRequest r, Metadata m, DateTime? dt, CancellationToken ct) =>
|
||||
{
|
||||
Verifier.CheckRequest(r);
|
||||
|
||||
PutSingleRequests.Add(r);
|
||||
|
||||
return new AsyncUnaryCall<PutSingleResponse>(
|
||||
Task.FromResult(putSingleResponse),
|
||||
Task.FromResult(ResponseMetaData),
|
||||
() => new Grpc.Core.Status(StatusCode.OK, string.Empty),
|
||||
() => ResponseMetaData,
|
||||
() => { });
|
||||
});
|
||||
|
||||
if (ObjectId != null)
|
||||
{
|
||||
DeleteResponse deleteResponse = new()
|
||||
{
|
||||
Body = new DeleteResponse.Types.Body
|
||||
{
|
||||
Tombstone = new Refs.Address
|
||||
{
|
||||
ContainerId = ObjectHeader!.ContainerId.ToGrpcMessage(),
|
||||
ObjectId = ObjectId.ToGrpcMessage()
|
||||
}
|
||||
},
|
||||
MetaHeader = ResponseMetaHeader
|
||||
};
|
||||
|
||||
deleteResponse.VerifyHeader = GetResponseVerificationHeader(deleteResponse);
|
||||
|
||||
mock.Setup(x => x.DeleteAsync(
|
||||
It.IsAny<DeleteRequest>(),
|
||||
It.IsAny<Metadata>(),
|
||||
It.IsAny<DateTime?>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.Returns((DeleteRequest r, Metadata m, DateTime? dt, CancellationToken ct) =>
|
||||
{
|
||||
Verifier.CheckRequest(r);
|
||||
|
||||
DeleteRequests.Add(r);
|
||||
|
||||
return new AsyncUnaryCall<DeleteResponse>(
|
||||
Task.FromResult(deleteResponse),
|
||||
Task.FromResult(ResponseMetaData),
|
||||
() => new Grpc.Core.Status(StatusCode.OK, string.Empty),
|
||||
() => ResponseMetaData,
|
||||
() => { });
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return mock;
|
||||
}
|
||||
|
||||
public ObjectHeader ObjectHeader { get; set; }
|
||||
}
|
||||
|
||||
public class AsyncStreamReaderMock(string key, ObjectHeader objectHeader) : ServiceBase(key), IAsyncStreamReader<GetResponse>
|
||||
{
|
||||
public GetResponse Current
|
||||
{
|
||||
get
|
||||
{
|
||||
var ecdsaKey = key.LoadWif();
|
||||
|
||||
var header = new Header
|
||||
{
|
||||
ContainerId = objectHeader.ContainerId.ToGrpcMessage(),
|
||||
PayloadLength = objectHeader.PayloadLength,
|
||||
Version = objectHeader.Version!.ToGrpcMessage(),
|
||||
OwnerId = objectHeader.OwnerId!.ToGrpcMessage()
|
||||
};
|
||||
|
||||
foreach (var attr in objectHeader.Attributes)
|
||||
header.Attributes.Add(attr.ToGrpcMessage());
|
||||
|
||||
var response = new GetResponse
|
||||
{
|
||||
Body = new GetResponse.Types.Body
|
||||
{
|
||||
Init = new GetResponse.Types.Body.Types.Init
|
||||
{
|
||||
Header = header,
|
||||
ObjectId = new Refs.ObjectID { Value = ByteString.CopyFrom(SHA256.HashData(Array.Empty<byte>())) },
|
||||
Signature = new Refs.Signature
|
||||
{
|
||||
Key = ByteString.CopyFrom(ecdsaKey.PublicKey()),
|
||||
Sign = ByteString.CopyFrom(ecdsaKey.SignData(header.ToByteArray())),
|
||||
}
|
||||
}
|
||||
},
|
||||
MetaHeader = new ResponseMetaHeader()
|
||||
};
|
||||
|
||||
response.VerifyHeader = GetResponseVerificationHeader(response);
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
public Task<bool> MoveNext(CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
public ObjectId? ObjectId { get; set; }
|
||||
|
||||
public ObjectHeader? ObjectHeader { get; set; }
|
||||
|
||||
public Header? HeadResponse { get; set; }
|
||||
|
||||
public byte[]? ResultObjectId { get; set; }
|
||||
|
||||
public ClientStreamWriter? ClientStreamWriter { get; private set; } = new ();
|
||||
|
||||
public List<PutSingleRequest> PutSingleRequests { get; private set; } = [];
|
||||
|
||||
public List<DeleteRequest> DeleteRequests { get; private set; } = [];
|
||||
|
||||
public List<HeadRequest> HeadRequests { get; private set; } = [];
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ using Google.Protobuf;
|
|||
|
||||
namespace FrostFS.SDK.Tests;
|
||||
|
||||
public class SessionMockFactory(string key) : ServiceBase(key)
|
||||
public class SessionMocker(string key) : ServiceBase(key)
|
||||
{
|
||||
public byte[]? SessionId { get; set; }
|
||||
|
||||
|
|
|
@ -1,66 +1,237 @@
|
|||
using FrostFS.Refs;
|
||||
using FrostFS.SDK.ClientV2;
|
||||
using FrostFS.SDK.ClientV2.Interfaces;
|
||||
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
using FrostFS.SDK.ModelsV2.Enums;
|
||||
using FrostFS.SDK.ModelsV2.Netmap;
|
||||
using Google.Protobuf;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace FrostFS.SDK.Tests;
|
||||
|
||||
public class ObjectTest
|
||||
public abstract class ObjectTestsBase
|
||||
{
|
||||
private readonly string key = "KwHDAJ66o8FoLBjVbjP2sWBmgBMGjt7Vv4boA7xQrBoAYBE397Aq";
|
||||
protected static readonly string key = "KwHDAJ66o8FoLBjVbjP2sWBmgBMGjt7Vv4boA7xQrBoAYBE397Aq";
|
||||
|
||||
[Fact]
|
||||
public async void GetObjectTest()
|
||||
protected IOptions<ClientSettings> Settings { get; set; }
|
||||
protected ContainerId ContainerId { get; set; }
|
||||
|
||||
protected NetworkMocker NetworkMocker { get; set; } = new NetworkMocker(key);
|
||||
protected SessionMocker SessionMocker { get; set; } = new SessionMocker(key);
|
||||
protected ContainerMocker ContainerMocker { get; set; } = new ContainerMocker(key);
|
||||
protected ObjectMocker Mocker { get; set; }
|
||||
|
||||
protected ObjectTestsBase()
|
||||
{
|
||||
var ecdsaKey = key.LoadWif();
|
||||
ContainerId cntId = new("xyz");
|
||||
|
||||
ObjectHeader header = new(cntId, ModelsV2.Enums.ObjectType.Regular, [new ObjectAttribute("k", "v")])
|
||||
{
|
||||
PayloadLength = 1,
|
||||
Version = new ModelsV2.Version(2, 13),
|
||||
OwnerId = OwnerId.FromKey(ecdsaKey)
|
||||
};
|
||||
|
||||
var objectMockFactory = new ObjectMockFactory(this.key)
|
||||
{
|
||||
PlacementPolicy = new PlacementPolicy(true, new Replica(1)),
|
||||
Version = new ModelsV2.Version(2, 13),
|
||||
ContainerGuid = Guid.NewGuid(),
|
||||
ObjectHeader = header
|
||||
};
|
||||
|
||||
var settings = Options.Create(new ClientSettings
|
||||
Settings = Options.Create(new ClientSettings
|
||||
{
|
||||
Key = key,
|
||||
Host = "http://localhost:8080"
|
||||
});
|
||||
|
||||
var fsClient = Client.GetTestInstance(
|
||||
settings,
|
||||
Mocker = new ObjectMocker(key)
|
||||
{
|
||||
PlacementPolicy = new PlacementPolicy(true, new Replica(1)),
|
||||
Version = new ModelsV2.Version(2, 13),
|
||||
ContainerGuid = Guid.NewGuid()
|
||||
};
|
||||
|
||||
ContainerId = new ContainerId(Base58.Encode(Mocker.ContainerGuid.ToBytes()));
|
||||
|
||||
Mocker.ObjectHeader = new(ContainerId, ModelsV2.Enums.ObjectType.Regular, [new ObjectAttribute("k", "v")])
|
||||
{
|
||||
PayloadLength = 1,
|
||||
Version = new ModelsV2.Version(2, 13),
|
||||
OwnerId = OwnerId.FromKey(ecdsaKey)
|
||||
};
|
||||
}
|
||||
|
||||
protected IFrostFSClient GetClient()
|
||||
{
|
||||
return Client.GetTestInstance(
|
||||
Settings,
|
||||
null,
|
||||
new NetmapMockFactory(this.key).GetMock().Object,
|
||||
new SessionMockFactory(this.key).GetMock().Object,
|
||||
new ContainerStub(this.key).GetMock().Object,
|
||||
objectMockFactory.GetMock().Object);
|
||||
NetworkMocker.GetMock().Object,
|
||||
SessionMocker.GetMock().Object,
|
||||
ContainerMocker.GetMock().Object,
|
||||
Mocker.GetMock().Object);
|
||||
}
|
||||
}
|
||||
|
||||
var objectId = fsClient.CalculateObjectId(header);
|
||||
public class ObjectTest : ObjectTestsBase
|
||||
{
|
||||
[Fact]
|
||||
public async void GetObjectTest()
|
||||
{
|
||||
var client = GetClient();
|
||||
var objectId = client.CalculateObjectId(Mocker.ObjectHeader!);
|
||||
|
||||
var containerId = new ContainerId(Base58.Encode(objectMockFactory.ContainerGuid.ToBytes()));
|
||||
var context = new Context
|
||||
{
|
||||
Timeout = TimeSpan.FromSeconds(2)
|
||||
};
|
||||
|
||||
var result = await fsClient.GetObjectAsync(containerId, objectId);
|
||||
var result = await client.GetObjectAsync(ContainerId, objectId, context);
|
||||
|
||||
Assert.NotNull(result);
|
||||
|
||||
Assert.Equal(header.ContainerId.Value, result.Header.ContainerId.Value);
|
||||
Assert.Equal(header.OwnerId.ToGrpcMessage().ToString(), result.Header.OwnerId!.Value);
|
||||
Assert.Equal(header.PayloadLength, result.Header.PayloadLength);
|
||||
Assert.Equal(Mocker.ObjectHeader!.ContainerId.Value, result.Header.ContainerId.Value);
|
||||
Assert.Equal(Mocker.ObjectHeader!.OwnerId!.ToGrpcMessage().ToString(), result.Header.OwnerId!.Value);
|
||||
Assert.Equal(Mocker.ObjectHeader.PayloadLength, result.Header.PayloadLength);
|
||||
Assert.Single(result.Header.Attributes);
|
||||
Assert.Equal(header.Attributes[0].Key, result.Header.Attributes[0].Key);
|
||||
Assert.Equal(header.Attributes[0].Value,result.Header.Attributes[0].Value);
|
||||
Assert.Equal(Mocker.ObjectHeader.Attributes[0].Key, result.Header.Attributes[0].Key);
|
||||
Assert.Equal(Mocker.ObjectHeader.Attributes[0].Value,result.Header.Attributes[0].Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void PutObjectTest()
|
||||
{
|
||||
Mocker.ResultObjectId = SHA256.HashData([]);
|
||||
|
||||
Random rnd = new();
|
||||
var bytes = new byte[1024];
|
||||
rnd.NextBytes(bytes);
|
||||
|
||||
var param = new PutObjectParameters
|
||||
{
|
||||
Header = Mocker.ObjectHeader,
|
||||
Payload = new MemoryStream(bytes),
|
||||
ClientCut = false
|
||||
};
|
||||
|
||||
var result = await GetClient().PutObjectAsync(param);
|
||||
|
||||
var sentMessages = Mocker.ClientStreamWriter!.Messages;
|
||||
|
||||
var body1 = sentMessages.ElementAt(0).GetBody() as Object.PutRequest.Types.Body;
|
||||
var body2 = sentMessages.ElementAt(1).GetBody() as Object.PutRequest.Types.Body;
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(Mocker.ResultObjectId, result.ToHash());
|
||||
|
||||
Assert.True(Mocker.ClientStreamWriter.CompletedTask);
|
||||
|
||||
Assert.Equal(0, body1!.Chunk.Length);
|
||||
Assert.Equal(Object.PutRequest.Types.Body.ObjectPartOneofCase.Init, body1!.ObjectPartCase);
|
||||
|
||||
Assert.Equal(1024, body2!.Chunk.Length);
|
||||
Assert.Equal(Object.PutRequest.Types.Body.ObjectPartOneofCase.Chunk, body2!.ObjectPartCase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void ClientCutTest()
|
||||
{
|
||||
NetworkMocker.Parameters = new Dictionary<string, byte[]>() { { "MaxObjectSize", [0x0, 0xa] } };
|
||||
|
||||
var blockSize = 2560;
|
||||
byte[] bytes = File.ReadAllBytes(@".\..\..\..\TestData\cat.jpg");
|
||||
var fileLength = bytes.Length;
|
||||
|
||||
var param = new PutObjectParameters
|
||||
{
|
||||
Header = Mocker.ObjectHeader,
|
||||
Payload = new MemoryStream(bytes),
|
||||
ClientCut = true
|
||||
};
|
||||
|
||||
var result = await GetClient().PutObjectAsync(param);
|
||||
|
||||
var sentMessages = Mocker.PutSingleRequests.ToArray();
|
||||
|
||||
Assert.Equal(4, sentMessages.Length);
|
||||
|
||||
var object_0 = sentMessages[0].Body.Object;
|
||||
var object_1 = sentMessages[1].Body.Object;
|
||||
var object_2 = sentMessages[2].Body.Object;
|
||||
var object_3 = sentMessages[3].Body.Object;
|
||||
|
||||
Assert.NotNull(object_0.Header.Split.SplitId);
|
||||
Assert.Null(object_0.Header.Split.Previous);
|
||||
Assert.Equal(blockSize, (int)object_0.Header.PayloadLength);
|
||||
Assert.Equal(bytes[..blockSize], object_0.Payload);
|
||||
Assert.True(object_0.Header.Attributes.Count == 0);
|
||||
|
||||
Assert.Equal(object_0.Header.Split.SplitId, object_1.Header.Split.SplitId);
|
||||
Assert.Equal(object_0.ObjectId, object_1.Header.Split.Previous);
|
||||
Assert.Equal(blockSize, (int)object_1.Header.PayloadLength);
|
||||
Assert.Equal(bytes[blockSize..(blockSize * 2)], object_1.Payload);
|
||||
Assert.True(object_1.Header.Attributes.Count == 0);
|
||||
|
||||
// last part
|
||||
Assert.NotNull(object_2.Header.Split.Parent);
|
||||
Assert.NotNull(object_2.Header.Split.ParentHeader);
|
||||
Assert.NotNull(object_2.Header.Split.ParentSignature);
|
||||
Assert.Equal(object_1.Header.Split.SplitId, object_2.Header.Split.SplitId);
|
||||
Assert.Equal(object_1.ObjectId, object_2.Header.Split.Previous);
|
||||
Assert.Equal(fileLength%blockSize, (int)object_2.Header.PayloadLength);
|
||||
Assert.Equal(bytes[((fileLength/blockSize) * blockSize)..fileLength], object_2.Payload);
|
||||
Assert.True(object_2.Header.Attributes.Count == 0);
|
||||
|
||||
// link object
|
||||
Assert.Equal(object_2.Header.Split.Parent, object_3.Header.Split.Parent);
|
||||
Assert.Equal(object_2.Header.Split.ParentHeader, object_3.Header.Split.ParentHeader);
|
||||
Assert.Equal(object_2.Header.Split.SplitId, object_3.Header.Split.SplitId);
|
||||
Assert.Equal(0, (int)object_3.Header.PayloadLength);
|
||||
Assert.Contains(object_0.ObjectId, object_3.Header.Split.Children);
|
||||
Assert.Contains(object_2.ObjectId, object_3.Header.Split.Children);
|
||||
Assert.Contains(object_2.ObjectId, object_3.Header.Split.Children);
|
||||
Assert.True(object_2.Header.Attributes.Count == 0);
|
||||
|
||||
Assert.Single(object_3.Header.Split.ParentHeader.Attributes);
|
||||
Assert.Equal("k", object_3.Header.Split.ParentHeader.Attributes[0].Key);
|
||||
Assert.Equal("v", object_3.Header.Split.ParentHeader.Attributes[0].Value);
|
||||
|
||||
var modelObjId = ObjectId.FromHash(object_3.Header.Split.Parent.Value.ToByteArray());
|
||||
|
||||
Assert.Equal(result.Value, modelObjId.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void DeleteObject()
|
||||
{
|
||||
Mocker.ObjectId = new ObjectID { Value = ByteString.CopyFrom(SHA256.HashData(Encoding.UTF8.GetBytes("test"))) }.ToModel();
|
||||
|
||||
await GetClient().DeleteObjectAsync(ContainerId, Mocker.ObjectId);
|
||||
|
||||
var request = Mocker.DeleteRequests.FirstOrDefault();
|
||||
Assert.NotNull(request);
|
||||
Assert.Equal(ContainerId.ToGrpcMessage(), request.Body.Address.ContainerId);
|
||||
Assert.Equal(Mocker.ObjectId.ToGrpcMessage(), request.Body.Address.ObjectId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void GetHeaderTest()
|
||||
{
|
||||
Mocker.ObjectId = new ObjectID { Value = ByteString.CopyFrom(SHA256.HashData(Encoding.UTF8.GetBytes("test"))) }.ToModel();
|
||||
|
||||
var response = await GetClient().GetObjectHeadAsync(ContainerId, Mocker.ObjectId);
|
||||
|
||||
var request = Mocker.HeadRequests.FirstOrDefault();
|
||||
Assert.NotNull(request);
|
||||
Assert.Equal(ContainerId.ToGrpcMessage(), request.Body.Address.ContainerId);
|
||||
Assert.Equal(Mocker.ObjectId.ToGrpcMessage(), request.Body.Address.ObjectId);
|
||||
|
||||
Assert.NotNull(response);
|
||||
Assert.Equal(ContainerId.Value, response.ContainerId.Value);
|
||||
|
||||
Assert.Equal(Mocker.ObjectHeader!.OwnerId!.ToGrpcMessage().ToString(), response.OwnerId!.Value);
|
||||
Assert.Equal(Mocker.ObjectHeader!.Version!.ToString(), response.Version!.ToString());
|
||||
|
||||
Assert.Equal(Mocker.HeadResponse!.PayloadLength, response.PayloadLength);
|
||||
|
||||
Assert.Equal(ObjectType.Regular, response.ObjectType);
|
||||
|
||||
Assert.Single(response.Attributes);
|
||||
|
||||
Assert.Equal(Mocker.HeadResponse.Attributes[0].Key, response.Attributes.First().Key);
|
||||
Assert.Equal(Mocker.HeadResponse.Attributes[0].Value, response.Attributes.First().Value);
|
||||
|
||||
Assert.Null(response.Split);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,14 +5,13 @@ using FrostFS.SDK.ModelsV2;
|
|||
using FrostFS.SDK.ModelsV2.Enums;
|
||||
using FrostFS.SDK.ModelsV2.Netmap;
|
||||
using Grpc.Core;
|
||||
using Grpc.Net.Client;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Grpc.Core.Interceptors;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace FrostFS.SDK.Tests;
|
||||
namespace FrostFS.SDK.SmokeTests;
|
||||
|
||||
public class ClientTestLive
|
||||
public class SmokeTests
|
||||
{
|
||||
private readonly string key = "KwHDAJ66o8FoLBjVbjP2sWBmgBMGjt7Vv4boA7xQrBoAYBE397Aq";
|
||||
private readonly string url = "http://172.29.238.97:8080";
|
||||
|
@ -46,11 +45,24 @@ public class ClientTestLive
|
|||
Assert.Equal(2, result.Version.Major);
|
||||
Assert.Equal(13, result.Version.Minor);
|
||||
Assert.Equal(NodeState.Online, result.State);
|
||||
Assert.True(result.PublicKey.Length > 0);
|
||||
Assert.Equal(33, result.PublicKey.Length);
|
||||
Assert.Single(result.Addresses);
|
||||
Assert.Equal(9, result.Attributes.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void NodeInfo_Statictics_Test()
|
||||
{
|
||||
var ctx = new Context
|
||||
{
|
||||
Callback = (cs) => Console.WriteLine($"{cs.MethodName} took {cs.ElapsedMicroSeconds} microseconds")
|
||||
};
|
||||
|
||||
using var fsClient = Client.GetInstance(GetOptions(this.key, this.url));
|
||||
|
||||
var result = await fsClient.GetNodeInfoAsync();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void SimpleScenarioTest()
|
||||
{
|
||||
|
@ -76,9 +88,7 @@ public class ClientTestLive
|
|||
|
||||
Assert.NotNull(container);
|
||||
|
||||
Random rnd = new();
|
||||
var bytes = new byte[6 * 1024 * 1024 + 100];
|
||||
rnd.NextBytes(bytes);
|
||||
var bytes = GetRandomBytes(6 * 1024 * 1024 + 100);
|
||||
|
||||
var param = new PutObjectParameters
|
||||
{
|
||||
|
@ -141,25 +151,21 @@ public class ClientTestLive
|
|||
|
||||
await Cleanup(fsClient);
|
||||
|
||||
var containerId = await fsClient.CreateContainerAsync(
|
||||
new ModelsV2.Container(BasicAcl.PublicRW, new PlacementPolicy(true, new Replica(1))));
|
||||
var cnt = new ModelsV2.Container(BasicAcl.PublicRW, new PlacementPolicy(true, new Replica(1)));
|
||||
|
||||
var context = new Context
|
||||
{
|
||||
Timeout = TimeSpan.FromSeconds(10)
|
||||
var containerId = await fsClient.CreateContainerAsync(cnt);
|
||||
|
||||
var context = new Context
|
||||
{
|
||||
Timeout = TimeSpan.FromSeconds(10),
|
||||
Interceptors = new([new MetricsInterceptor()])
|
||||
};
|
||||
|
||||
var metrics = new MetricsInterceptor();
|
||||
|
||||
context.Interceptors.Add(metrics);
|
||||
|
||||
var container = await GetContainer(fsClient, containerId, context);
|
||||
|
||||
Assert.NotNull(container);
|
||||
|
||||
Random rnd = new();
|
||||
var bytes = new byte[6 * 1024 * 1024 + 100];
|
||||
rnd.NextBytes(bytes);
|
||||
byte[] bytes = GetRandomBytes(150 * 1024 * 1024);
|
||||
|
||||
var param = new PutObjectParameters
|
||||
{
|
||||
|
@ -200,6 +206,8 @@ public class ClientTestLive
|
|||
ms.Write(chunk);
|
||||
}
|
||||
|
||||
Assert.Equal(MD5.HashData(bytes), MD5.HashData(downloadedBytes));
|
||||
|
||||
await Cleanup(fsClient);
|
||||
|
||||
await Task.Delay(2000);
|
||||
|
@ -210,15 +218,21 @@ public class ClientTestLive
|
|||
}
|
||||
}
|
||||
|
||||
private static byte[] GetRandomBytes(int size)
|
||||
{
|
||||
Random rnd = new();
|
||||
var bytes = new byte[size];
|
||||
rnd.NextBytes(bytes);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private static IOptions<ClientSettings> GetOptions(string key, string url)
|
||||
{
|
||||
var settings = new ClientSettings
|
||||
return Options.Create(new ClientSettings
|
||||
{
|
||||
Key = key,
|
||||
Host = url
|
||||
};
|
||||
|
||||
return Options.Create(settings);
|
||||
});
|
||||
}
|
||||
|
||||
static async Task Cleanup(IFrostFSClient fsClient)
|
||||
|
@ -243,7 +257,7 @@ public class ClientTestLive
|
|||
if (DateTime.UtcNow >= ctx.Deadline)
|
||||
throw new TimeoutException();
|
||||
}
|
||||
catch (Grpc.Core.RpcException)
|
||||
catch (RpcException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
@ -268,7 +282,7 @@ public class MetricsInterceptor() : Interceptor
|
|||
call.Dispose);
|
||||
}
|
||||
|
||||
private async Task<TResponse> HandleUnaryResponse<TResponse>(AsyncUnaryCall<TResponse> call)
|
||||
private static async Task<TResponse> HandleUnaryResponse<TResponse>(AsyncUnaryCall<TResponse> call)
|
||||
{
|
||||
var watch = new Stopwatch();
|
||||
watch.Start();
|
BIN
src/FrostFS.SDK.Tests/TestData/cat.jpg
Normal file
BIN
src/FrostFS.SDK.Tests/TestData/cat.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.6 KiB |
Loading…
Reference in a new issue