[#14] Add interceptors
All checks were successful
DCO / DCO (pull_request) Successful in 43s
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:
parent
605463ec24
commit
ae67b12313
28 changed files with 943 additions and 554 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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]) }
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// });
|
||||
|
||||
|
||||
|
|
@ -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())),
|
||||
// }
|
||||
// }
|
||||
|
||||
// };
|
||||
// });
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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>();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
{
|
|
@ -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()
|
||||
{
|
101
src/FrostFS.SDK.Tests/Mocks/ObjectMock.cs
Normal file
101
src/FrostFS.SDK.Tests/Mocks/ObjectMock.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
|
57
src/FrostFS.SDK.Tests/Mocks/SessionMock.cs
Normal file
57
src/FrostFS.SDK.Tests/Mocks/SessionMock.cs
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
66
src/FrostFS.SDK.Tests/ObjectTest.cs
Normal file
66
src/FrostFS.SDK.Tests/ObjectTest.cs
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue