[#14] Add interceptors
All checks were successful
DCO / DCO (pull_request) Successful in 43s

Signed-off-by: Pavel Gross <p.gross@yadro.com>
This commit is contained in:
Pavel Gross 2024-07-01 11:56:47 +03:00 committed by p.gross
parent 605463ec24
commit ae67b12313
28 changed files with 943 additions and 554 deletions

View file

@ -7,6 +7,8 @@ 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;
@ -18,13 +20,7 @@ public class ClientTestLive
[Fact]
public async void NetworkMapTest()
{
var channelOptions = new GrpcChannelOptions
{
Credentials = ChannelCredentials.Insecure,
HttpHandler = new HttpClientHandler()
};
using var fsClient = Client.GetInstance(GetOptions(this.key, this.url), channelOptions);
using var fsClient = Client.GetInstance(GetOptions(this.key, this.url));
var result = await fsClient.GetNetmapSnapshotAsync();
@ -36,20 +32,14 @@ public class ClientTestLive
Assert.Equal(13, item.Version.Minor);
Assert.Equal(NodeState.Online, item.State);
Assert.True(item.PublicKey.Length > 0);
Assert.Single(item.Addresses);
Assert.Single(item.Addresses);
Assert.Equal(9, item.Attributes.Count);
}
[Fact]
public async void NodeInfoTest()
{
var channelOptions = new GrpcChannelOptions
{
Credentials = ChannelCredentials.Insecure,
HttpHandler = new HttpClientHandler()
};
using var fsClient = Client.GetInstance(GetOptions(this.key, this.url), channelOptions);
using var fsClient = Client.GetInstance(GetOptions(this.key, this.url));
var result = await fsClient.GetNodeInfoAsync();
@ -64,27 +54,30 @@ public class ClientTestLive
[Fact]
public async void SimpleScenarioTest()
{
var channelOptions = new GrpcChannelOptions
{
Credentials = ChannelCredentials.Insecure,
HttpHandler = new HttpClientHandler()
};
using var fsClient = Client.GetInstance(GetOptions(this.key, this.url));
using var fsClient = Client.GetInstance(GetOptions(this.key, this.url), channelOptions);
await Cleanup(fsClient);
var containerId = await fsClient.CreateContainerAsync(
new ModelsV2.Container(BasicAcl.PublicRW, new PlacementPolicy(true, new Replica(1))));
new ModelsV2.Container(BasicAcl.PublicRW, new PlacementPolicy(true, new Replica(1))),
new Context
{
Callback = new((CallStatistics cs) => Assert.True(cs.ElapsedMicroSeconds > 0))
}
);
var context = new Context { Timeout = TimeSpan.FromSeconds(10) };
var context = new Context
{
Timeout = TimeSpan.FromSeconds(10),
Callback = new((CallStatistics cs) => Assert.True(cs.ElapsedMicroSeconds > 0))
};
var container = await GetContainer(fsClient, containerId, context);
Assert.NotNull(container);
Random rnd = new();
var bytes = new byte[6*1024*1024 + 100];
var bytes = new byte[6 * 1024 * 1024 + 100];
rnd.NextBytes(bytes);
var param = new PutObjectParameters
@ -97,7 +90,10 @@ public class ClientTestLive
ClientCut = false
};
var objectId = await fsClient.PutObjectAsync(param);
var objectId = await fsClient.PutObjectAsync(param, new Context
{
Callback = new((CallStatistics cs) => Assert.True(cs.ElapsedMicroSeconds > 0))
});
var filter = new ObjectFilter(ObjectMatchType.Equals, "fileName", "test");
@ -121,7 +117,7 @@ public class ClientTestLive
MemoryStream ms = new(downloadedBytes);
byte[]? chunk = null;
while ((chunk = await @object.ObjectReader.ReadChunk()) != null)
while ((chunk = await @object.ObjectReader!.ReadChunk()) != null)
{
ms.Write(chunk);
}
@ -141,26 +137,28 @@ public class ClientTestLive
[Fact]
public async void ClientCutScenarioTest()
{
var channelOptions = new GrpcChannelOptions
{
Credentials = ChannelCredentials.Insecure,
HttpHandler = new HttpClientHandler()
};
using var fsClient = Client.GetInstance(GetOptions(this.key, this.url), channelOptions);
using var fsClient = Client.GetInstance(GetOptions(this.key, this.url));
await Cleanup(fsClient);
var containerId = await fsClient.CreateContainerAsync(
new ModelsV2.Container(BasicAcl.PublicRW, new PlacementPolicy(true, new Replica(1))));
var context = new Context { Timeout = TimeSpan.FromSeconds(10) };
var context = new Context
{
Timeout = TimeSpan.FromSeconds(10)
};
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];
var bytes = new byte[6 * 1024 * 1024 + 100];
rnd.NextBytes(bytes);
var param = new PutObjectParameters
@ -193,11 +191,11 @@ public class ClientTestLive
var @object = await fsClient.GetObjectAsync(containerId, objectId!);
var downloadedBytes = new byte[@object.Header.PayloadLength];
var downloadedBytes = new byte[@object.Header.PayloadLength];
MemoryStream ms = new(downloadedBytes);
byte[]? chunk = null;
while ((chunk = await @object.ObjectReader.ReadChunk()) != null)
while ((chunk = await @object.ObjectReader!.ReadChunk()) != null)
{
ms.Write(chunk);
}
@ -237,7 +235,7 @@ public class ClientTestLive
{
try
{
await Task.Delay(100);
await Task.Delay(100);
return await fsClient.GetContainerAsync(id, ctx);
}
catch (ApplicationException)
@ -252,3 +250,35 @@ public class ClientTestLive
}
}
}
public class MetricsInterceptor() : Interceptor
{
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(
TRequest request,
ClientInterceptorContext<TRequest, TResponse> context,
AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
{
var call = continuation(request, context);
return new AsyncUnaryCall<TResponse>(
HandleUnaryResponse(call),
call.ResponseHeadersAsync,
call.GetStatus,
call.GetTrailers,
call.Dispose);
}
private async Task<TResponse> HandleUnaryResponse<TResponse>(AsyncUnaryCall<TResponse> call)
{
var watch = new Stopwatch();
watch.Start();
var response = await call.ResponseAsync;
watch.Stop();
var elapsed = watch.ElapsedTicks * 1_000_000/Stopwatch.Frequency;
return response;
}
}

View file

@ -1,28 +0,0 @@
using System.Security.Cryptography;
using FrostFS.Container;
using Moq;
using FrostFS.SDK.Cryptography;
using FrostFS.SDK.ModelsV2.Enums;
using FrostFS.SDK.ModelsV2.Netmap;
namespace FrostFS.SDK.Tests;
public abstract class ServiceBase(string key)
{
public ECDsa Key { get; private set; } = key.LoadWif();
public ModelsV2.Version Version { get; set; } = DefaultVersion;
public BasicAcl Acl { get; set; } = DefaultAcl;
public PlacementPolicy PlacementPolicy { get; set; } = DefaultPlacementPolicy;
public static ModelsV2.Version DefaultVersion { get; } = new(2, 13);
public static BasicAcl DefaultAcl { get; } = BasicAcl.PublicRW;
public static PlacementPolicy DefaultPlacementPolicy { get; } = new PlacementPolicy(true, new Replica(1));
}
public abstract class ContainerServiceBase(string key) : ServiceBase (key)
{
public Guid ContainerGuid { get; set; } = Guid.NewGuid();
public abstract Mock<ContainerService.ContainerServiceClient> GetMock();
}

View file

@ -1,69 +0,0 @@
using FrostFS.Container;
using FrostFS.Session;
using Google.Protobuf;
using Grpc.Core;
using Moq;
namespace FrostFS.SDK.Tests;
public class DeleteContainerMock(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>()));
v.Returns((Object.DeleteRequest r, Metadata m, DateTime? dt, CancellationToken ct) =>
{
var deleteResponse = new Object.DeleteResponse
{
Body = new Object.DeleteResponse.Types.Body
{
Tombstone = new Refs.Address
{
ContainerId = new Refs.ContainerID { Value = ByteString.CopyFrom([1, 2, 3]) },
ObjectId = new Refs.ObjectID { Value = ByteString.CopyFrom([4, 5, 6]) }
}
},
MetaHeader = new ResponseMetaHeader()
};
var metadata = new Metadata();
return new AsyncUnaryCall<Object.DeleteResponse>(
Task.FromResult(deleteResponse),
Task.FromResult(metadata),
() => new Grpc.Core.Status(StatusCode.OK, string.Empty),
() => metadata,
() => { });
});
return mock;
}
}
// objectServiceClientMock.Setup(x => x.Head(It.IsAny<Object.HeadRequest>(), It.IsAny<Metadata>(), It.IsAny<DateTime>(), It.IsAny<CancellationToken>()))
// .Returns((Object.DeleteRequest r, Metadata m, DateTime dt, CancellationToken ct) =>
// {
// return new
// {
// Body = new Object.DeleteResponse.Types.Body
// {
// Tombstone = new Refs.Address
// {
// ContainerId = new Refs.ContainerID { Value = ByteString.CopyFrom([1, 2, 3]) },
// ObjectId = new Refs.ObjectID { Value = ByteString.CopyFrom([4, 5, 6]) }
// }
// }
// };
// });

View file

@ -1,163 +0,0 @@
using FrostFS.Container;
using FrostFS.Session;
using Google.Protobuf;
using Grpc.Core;
using Moq;
using FrostFS.SDK.Cryptography;
using FrostFS.SDK.ClientV2;
using FrostFS.SDK.ModelsV2.Netmap;
using FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap;
using FrostFS.SDK.ClientV2.Mappers.GRPC;
namespace FrostFS.SDK.Tests;
public class GetContainerMock(string key) : ContainerServiceBase(key)
{
public override Mock<ContainerService.ContainerServiceClient> GetMock()
{
var mock = new Mock<ContainerService.ContainerServiceClient>();
var grpcVersion = Version.ToGrpcMessage();
var getResponse = new GetResponse
{
Body = new GetResponse.Types.Body
{
Container = new Container.Container
{
Version = grpcVersion,
Nonce = ByteString.CopyFrom(ContainerGuid.ToBytes()),
BasicAcl = (uint)Acl,
PlacementPolicy = PlacementPolicy.ToGrpcMessage()
}
},
MetaHeader = new ResponseMetaHeader
{
Version = grpcVersion,
Epoch = 100,
Ttl = 1
}
};
getResponse.VerifyHeader = GetResponseVerificationHeader(getResponse);
var metadata = new Metadata();
var getContainerResponse = new AsyncUnaryCall<GetResponse>(
Task.FromResult(getResponse),
Task.FromResult(metadata),
() => new Grpc.Core.Status(StatusCode.OK, string.Empty),
() => metadata,
() => { });
mock.Setup(x => x.GetAsync(
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 getContainerResponse;
});
return mock;
}
private ResponseVerificationHeader GetResponseVerificationHeader(GetResponse response)
{
var verifyHeader = new ResponseVerificationHeader
{
MetaSignature = new Refs.Signature
{
Key = ByteString.CopyFrom(Key.PublicKey()),
Scheme = FrostFS.Refs.SignatureScheme.EcdsaRfc6979Sha256,
Sign = ByteString.CopyFrom(Key.SignData(response.MetaHeader.ToByteArray()))
},
BodySignature = new Refs.Signature
{
Key = ByteString.CopyFrom(Key.PublicKey()),
Scheme = FrostFS.Refs.SignatureScheme.EcdsaRfc6979Sha256,
Sign = ByteString.CopyFrom(Key.SignData(response.GetBody().ToByteArray()))
},
OriginSignature = new Refs.Signature
{
Key = ByteString.CopyFrom(Key.PublicKey()),
Scheme = FrostFS.Refs.SignatureScheme.EcdsaRfc6979Sha256,
Sign = ByteString.CopyFrom(Key.SignData([]))
}
};
return verifyHeader;
}
}
// objectServiceClientMock.Setup(
// x => x.Put(It.IsAny<Metadata>(), It.IsAny<DateTime>(), It.IsAny<CancellationToken>()))
// .Returns((Metadata m, DateTime dt, CancellationToken ct) =>
// {
// return new AsyncClientStreamingCall<FrostFS.Object.PutRequest, FrostFS.Object.PutResponse>(null, null, null, null, null, null);
// //IClientStreamWriter<TRequest> requestStream, Task<TResponse> responseAsync, Task<Metadata> responseHeadersAsync, Func<Status> getStatusFunc, Func<Metadata> getTrailersFunc, Action disposeAction
// });
// return objectServiceClientMock;
// }
// }
// public virtual global::FrostFS.Object.HeadResponse Head(global::FrostFS.Object.HeadRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
// {
// return Head(request, new grpc::CallOptions(headers, deadline, cancellationToken));
// }
// objectServiceClientMock.Setup(x => x.Head(It.IsAny<Object.HeadRequest>(), It.IsAny<Metadata>(), It.IsAny<DateTime>(), It.IsAny<CancellationToken>()))
// .Returns((Object.DeleteRequest r, Metadata m, DateTime dt, CancellationToken ct) =>
// {
// return new
// {
// Body = new Object.DeleteResponse.Types.Body
// {
// Tombstone = new Refs.Address
// {
// ContainerId = new Refs.ContainerID { Value = ByteString.CopyFrom([1, 2, 3]) },
// ObjectId = new Refs.ObjectID { Value = ByteString.CopyFrom([4, 5, 6]) }
// }
// }
// };
// });
// objectServiceClientMock.Setup(x => x.Delete(It.IsAny<Object.DeleteRequest>(), It.IsAny<Metadata>(), It.IsAny<DateTime?>(), It.IsAny<CancellationToken>()))
// .Returns((Object.DeleteRequest r, Metadata m, DateTime? dt, CancellationToken ct) =>
// {
// return new Object.DeleteResponse
// {
// Body = new Object.DeleteResponse.Types.Body
// {
// Tombstone = new Refs.Address
// {
// ContainerId = new Refs.ContainerID { Value = ByteString.CopyFrom([1, 2, 3]) },
// ObjectId = new Refs.ObjectID { Value = ByteString.CopyFrom([4, 5, 6]) }
// }
// },
// MetaHeader = new ResponseMetaHeader()
// {
// },
// VerifyHeader = new ResponseVerificationHeader()
// {
// MetaSignature = new Refs.Signature
// {
// Key = ByteString.CopyFrom(_key.PublicKey()),
// Scheme = Refs.SignatureScheme.EcdsaRfc6979Sha256,
// Sign = ByteString.CopyFrom(_key.SignData(Array.Empty<byte>()))
// // ByteString.CopyFrom(_key.SignData(grpcHeader.Split.Parent.ToByteArray())),
// }
// }
// };
// });

View file

@ -3,18 +3,20 @@ using FrostFS.SDK.Cryptography;
using FrostFS.SDK.ModelsV2;
using FrostFS.SDK.ModelsV2.Enums;
using FrostFS.SDK.ModelsV2.Netmap;
using FrostFS.SDK.ClientV2.Mappers.GRPC;
using Microsoft.Extensions.Options;
namespace FrostFS.SDK.Tests;
public class ClientTest
public class ContainerTest
{
private readonly string key = "KwHDAJ66o8FoLBjVbjP2sWBmgBMGjt7Vv4boA7xQrBoAYBE397Aq";
[Fact]
public async void CreateContainerTest()
{
var factory = new PutContainerMock(this.key)
var factory = new PutContainerMockFactory(this.key)
{
PlacementPolicy = new PlacementPolicy(true, new Replica(1)),
Version = new ModelsV2.Version(2, 13),
@ -30,10 +32,10 @@ public class ClientTest
var fsClient = Client.GetTestInstance(
settings,
null,
new NetmapMock(this.key).GetMock().Object,
new SessionMock(this.key).GetMock().Object,
new NetmapMockFactory(this.key).GetMock().Object,
new SessionMockFactory(this.key).GetMock().Object,
factory.GetMock().Object,
new ObjectMock(this.key).GetMock().Object);
new ObjectMockFactory(this.key).GetMock().Object);
var result = await fsClient.CreateContainerAsync(new ModelsV2.Container(BasicAcl.PublicRW, factory.PlacementPolicy));
@ -45,7 +47,7 @@ public class ClientTest
[Fact]
public async void GetContainerTest()
{
var factory = new GetContainerMock(this.key)
var factory = new GetContainerMockFactory(this.key)
{
PlacementPolicy = new PlacementPolicy(true, new Replica(1)),
Version = new ModelsV2.Version(2, 13),
@ -62,10 +64,10 @@ public class ClientTest
var fsClient = Client.GetTestInstance(
settings,
null,
new NetmapMock(this.key).GetMock().Object,
new SessionMock(this.key).GetMock().Object,
new NetmapMockFactory(this.key).GetMock().Object,
new SessionMockFactory(this.key).GetMock().Object,
factory.GetMock().Object,
new ObjectMock(this.key).GetMock().Object);
new ObjectMockFactory(this.key).GetMock().Object);
var cid = new ContainerId(Base58.Encode(factory.ContainerGuid.ToBytes()));
@ -80,8 +82,38 @@ public class ClientTest
Assert.Equal(factory.Version.ToString(), result.Version!.ToString());
}
// [Fact]
// public async void DeleteObjectAsyncTest()
// {
// }
[Fact]
public async void DeleteContainerAsyncTest()
{
var factory = new DeleteContainerMockFactory(this.key)
{
Version = new ModelsV2.Version(2, 13),
Acl = BasicAcl.PublicRW,
ContainerGuid = Guid.NewGuid(),
};
var settings = Options.Create(new ClientSettings
{
Key = key,
Host = "http://localhost:8080"
});
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()));
await fsClient.DeleteContainerAsync(cid);
Assert.Single(factory.Requests);
var request = factory.Requests.First();
Assert.Equal(cid.ToGrpcMessage(), request.Request.Body.ContainerId);
}
}

View file

@ -0,0 +1,78 @@
using System.Security.Cryptography;
using FrostFS.Container;
using Moq;
using FrostFS.SDK.Cryptography;
using FrostFS.SDK.ModelsV2.Enums;
using FrostFS.SDK.ModelsV2.Netmap;
using FrostFS.Session;
using Google.Protobuf;
using FrostFS.SDK.ClientV2;
using FrostFS.Object;
using Grpc.Core;
using FrostFS.SDK.ClientV2.Mappers.GRPC;
namespace FrostFS.SDK.Tests;
public abstract class ServiceBase(string key)
{
public ECDsa Key { get; private set; } = key.LoadWif();
public ModelsV2.Version Version { get; set; } = DefaultVersion;
public BasicAcl Acl { get; set; } = DefaultAcl;
public PlacementPolicy PlacementPolicy { get; set; } = DefaultPlacementPolicy;
public static ModelsV2.Version DefaultVersion { get; } = new(2, 13);
public static BasicAcl DefaultAcl { get; } = BasicAcl.PublicRW;
public static PlacementPolicy DefaultPlacementPolicy { get; } = new PlacementPolicy(true, new Replica(1));
public Metadata ResponseMetaData => [];
protected ResponseVerificationHeader GetResponseVerificationHeader(IResponse response)
{
var verifyHeader = new ResponseVerificationHeader
{
MetaSignature = new Refs.Signature
{
Key = ByteString.CopyFrom(Key.PublicKey()),
Scheme = Refs.SignatureScheme.EcdsaRfc6979Sha256,
Sign = ByteString.CopyFrom(Key.SignData(response.MetaHeader.ToByteArray()))
},
BodySignature = new Refs.Signature
{
Key = ByteString.CopyFrom(Key.PublicKey()),
Scheme = Refs.SignatureScheme.EcdsaRfc6979Sha256,
Sign = ByteString.CopyFrom(Key.SignData(response.GetBody().ToByteArray()))
},
OriginSignature = new Refs.Signature
{
Key = ByteString.CopyFrom(Key.PublicKey()),
Scheme = Refs.SignatureScheme.EcdsaRfc6979Sha256,
Sign = ByteString.CopyFrom(Key.SignData([]))
}
};
return verifyHeader;
}
public ResponseMetaHeader ResponseMetaHeader => new()
{
Version = Version.ToGrpcMessage(),
Epoch = 100,
Ttl = 1
};
}
public abstract class ContainerServiceBase(string key) : ServiceBase (key)
{
public Guid ContainerGuid { get; set; } = Guid.NewGuid();
public abstract Mock<ContainerService.ContainerServiceClient> GetMock();
}
public abstract class ObjectServiceBase(string key) : ServiceBase (key)
{
public abstract Mock<ObjectService.ObjectServiceClient> GetMock();
public Guid ContainerGuid { get; set; } = Guid.NewGuid();
}

View file

@ -0,0 +1,54 @@
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;
}

View file

@ -0,0 +1,13 @@
using FrostFS.Container;
using Moq;
namespace FrostFS.SDK.Tests;
public class ContainerStub(string key) : ContainerServiceBase(key)
{
public override Mock<ContainerService.ContainerServiceClient> GetMock()
{
return new Mock<ContainerService.ContainerServiceClient>();
}
}

View file

@ -0,0 +1,58 @@
using FrostFS.Container;
using Google.Protobuf;
using Grpc.Core;
using Moq;
using FrostFS.SDK.Cryptography;
using FrostFS.SDK.ClientV2;
using FrostFS.SDK.ModelsV2.Netmap;
using FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap;
using FrostFS.SDK.ClientV2.Mappers.GRPC;
namespace FrostFS.SDK.Tests;
public class GetContainerMockFactory(string key) : ContainerServiceBase(key)
{
public override Mock<ContainerService.ContainerServiceClient> GetMock()
{
var mock = new Mock<ContainerService.ContainerServiceClient>();
var grpcVersion = Version.ToGrpcMessage();
var response = new GetResponse
{
Body = new GetResponse.Types.Body
{
Container = new Container.Container
{
Version = grpcVersion,
Nonce = ByteString.CopyFrom(ContainerGuid.ToBytes()),
BasicAcl = (uint)Acl,
PlacementPolicy = PlacementPolicy.ToGrpcMessage()
}
},
MetaHeader = ResponseMetaHeader
};
response.VerifyHeader = GetResponseVerificationHeader(response);
mock.Setup(x => x.GetAsync(
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 AsyncUnaryCall<GetResponse>(
Task.FromResult(response),
Task.FromResult(ResponseMetaData),
() => new Grpc.Core.Status(StatusCode.OK, string.Empty),
() => ResponseMetaData,
() => { });
});
return mock;
}
}

View file

@ -11,7 +11,7 @@ using FrostFS.Refs;
namespace FrostFS.SDK.Tests;
public class PutContainerMock(string key) : ContainerServiceBase(key)
public class PutContainerMockFactory(string key) : ContainerServiceBase(key)
{
public override Mock<ContainerService.ContainerServiceClient> GetMock()
{

View file

@ -3,7 +3,7 @@ using FrostFS.Netmap;
namespace FrostFS.SDK.Tests;
public class NetmapMock(string key) : ServiceBase(key)
public class NetmapMockFactory(string key) : ServiceBase(key)
{
public Mock<NetmapService.NetmapServiceClient> GetMock()
{

View file

@ -0,0 +1,101 @@
using Moq;
using FrostFS.Object;
using Grpc.Core;
using FrostFS.SDK.ClientV2;
using FrostFS.Session;
using Google.Protobuf;
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 override Mock<ObjectService.ObjectServiceClient> GetMock()
{
var mock = new Mock<ObjectService.ObjectServiceClient>();
GetResponse response = new()
{
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) =>
{
Verifier.CheckRequest(r);
return new AsyncServerStreamingCall<GetResponse>(
new AsyncStreamReaderMock(key, ObjectHeader),
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);
}
}

View file

@ -0,0 +1,57 @@
using Moq;
using FrostFS.Session;
using Grpc.Core;
using FrostFS.SDK.ClientV2;
using Google.Protobuf;
namespace FrostFS.SDK.Tests;
public class SessionMockFactory(string key) : ServiceBase(key)
{
public byte[]? SessionId { get; set; }
public byte[]? SessionKey { get; set; }
public Mock<SessionService.SessionServiceClient> GetMock()
{
var mock = new Mock<SessionService.SessionServiceClient>();
Random rand = new();
SessionId = new byte[32];
SessionKey = new byte[32];
rand.NextBytes(SessionId);
rand.NextBytes(SessionKey);
CreateResponse response = new()
{
Body = new CreateResponse.Types.Body
{
Id = ByteString.CopyFrom(SessionId),
SessionKey = ByteString.CopyFrom(SessionId)
},
MetaHeader = ResponseMetaHeader
};
response.VerifyHeader = GetResponseVerificationHeader(response);
mock.Setup(x => x.CreateAsync(
It.IsAny<CreateRequest>(),
It.IsAny<Metadata>(),
It.IsAny<DateTime?>(),
It.IsAny<CancellationToken>()))
.Returns((CreateRequest r, Metadata m, DateTime? dt, CancellationToken ct) =>
{
Verifier.CheckRequest(r);
return new AsyncUnaryCall<CreateResponse>(
Task.FromResult(response),
Task.FromResult(ResponseMetaData),
() => new Grpc.Core.Status(StatusCode.OK, string.Empty),
() => ResponseMetaData,
() => { });
});
return mock;
}
}

View file

@ -1,14 +0,0 @@
using Moq;
using FrostFS.Object;
namespace FrostFS.SDK.Tests;
public class ObjectMock(string key) : ServiceBase(key)
{
public Mock<ObjectService.ObjectServiceClient> GetMock()
{
var mock = new Mock<ObjectService.ObjectServiceClient>();
return mock;
}
}

View file

@ -0,0 +1,66 @@
using FrostFS.SDK.ClientV2;
using FrostFS.SDK.ClientV2.Mappers.GRPC;
using FrostFS.SDK.Cryptography;
using FrostFS.SDK.ModelsV2;
using FrostFS.SDK.ModelsV2.Netmap;
using Microsoft.Extensions.Options;
using System.Security.Cryptography;
namespace FrostFS.SDK.Tests;
public class ObjectTest
{
private readonly string key = "KwHDAJ66o8FoLBjVbjP2sWBmgBMGjt7Vv4boA7xQrBoAYBE397Aq";
[Fact]
public async void GetObjectTest()
{
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
{
Key = key,
Host = "http://localhost:8080"
});
var fsClient = 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);
var objectId = fsClient.CalculateObjectId(header);
var containerId = new ContainerId(Base58.Encode(objectMockFactory.ContainerGuid.ToBytes()));
var result = await fsClient.GetObjectAsync(containerId, objectId);
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.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);
}
}

View file

@ -1,14 +0,0 @@
using Moq;
using FrostFS.Session;
namespace FrostFS.SDK.Tests;
public class SessionMock(string key) : ServiceBase(key)
{
public Mock<SessionService.SessionServiceClient> GetMock()
{
var mock = new Mock<SessionService.SessionServiceClient>();
return mock;
}
}