Skip to content

Commit

Permalink
[net]tests(remoting): introduce some basic tests for RemotingViaNodeC…
Browse files Browse the repository at this point in the history
…lient (#668)
  • Loading branch information
DennisInSky authored Nov 21, 2024
1 parent 702710a commit 98e0325
Show file tree
Hide file tree
Showing 11 changed files with 191 additions and 36 deletions.
1 change: 1 addition & 0 deletions Sails.Net.sln
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ Global
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{382EBE9F-C60C-4D20-A585-B3272113F944} = {19594BCA-94DB-44AD-ACBC-2ACFED242E9F}
{DEEACFC0-EE4D-42E5-9616-232242913A39} = {19594BCA-94DB-44AD-ACBC-2ACFED242E9F}
{A6A2172B-8F8F-4BDC-B519-E7299FFCCA5F} = {19594BCA-94DB-44AD-ACBC-2ACFED242E9F}
{42B621CE-C2B4-4911-961C-5B087A514AF5} = {19594BCA-94DB-44AD-ACBC-2ACFED242E9F}
Expand Down
3 changes: 2 additions & 1 deletion net/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<PackageVersion Include="coverlet.collector" Version="6.0.2" />
<PackageVersion Include="FluentAssertions" Version="6.12.2" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageVersion Include="Nito.AsyncEx" Version="5.1.2" />
<PackageVersion Include="NSubstitute" Version="5.3.0" />
Expand All @@ -27,7 +28,7 @@
<PackageVersion Include="NSubstitute.Analyzers.CSharp" Version="1.0.17" />
<PackageVersion Include="Roslynator.Analyzers" Version="4.12.9" />
<PackageVersion Include="Roslynator.Formatting.Analyzers" Version="4.12.9" />
<!-- Due to vulnarabilties -->
<!-- Due to Vulnarabilties -->
<PackageVersion Include="MessagePack" Version="2.5.192" />
<PackageVersion Include="System.Text.Json" Version="9.0.0" />
</ItemGroup>
Expand Down
6 changes: 6 additions & 0 deletions net/src/Sails.Remoting/Sails.Remoting.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,10 @@
<ProjectReference Include="..\Substrate.Gear.Client\Substrate.Gear.Client.csproj" />
</ItemGroup>

<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>Sails.Remoting.Tests</_Parameter1>
</AssemblyAttribute>
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Linq;
using EnsureThat;
using Substrate.NetApi;

namespace Substrate.Gear.Client.GearApi.Model.gprimitives;

public static class ActorIdExtensions
{
public static string ToHexString(this Api.Generated.Model.gprimitives.ActorId actorId)
{
EnsureArg.IsNotNull(actorId, nameof(actorId));
EnsureArg.IsNotNull(actorId.Value, "actorId.Value");
EnsureArg.IsNotNull(actorId.Value.Value, "actorId.Value.Value");

return Utils.Bytes2HexString(actorId.Value.Value.Select(u8 => u8.Value).ToArray());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Linq;
using EnsureThat;
using Substrate.NetApi;

namespace Substrate.Gear.Client.GearApi.Model.gprimitives;

public static class CodeIdExtensions
{
public static string ToHexString(this Api.Generated.Model.gprimitives.CodeId codeId)
{
EnsureArg.IsNotNull(codeId, nameof(codeId));
EnsureArg.IsNotNull(codeId.Value, "codeId.Value");
EnsureArg.IsNotNull(codeId.Value.Value, "codeId.Value.Value");

return Utils.Bytes2HexString(codeId.Value.Value.Select(u8 => u8.Value).ToArray());
}
}
17 changes: 11 additions & 6 deletions net/src/Substrate.Gear.Client/SubstrateClientExtExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using Substrate.Gear.Api.Generated.Model.sp_runtime;
using Substrate.Gear.Api.Generated.Model.vara_runtime;
using Substrate.Gear.Api.Generated.Storage;
using Substrate.Gear.Client.GearApi.Model.gprimitives;
using Substrate.Gear.Client.NetApi.Model.Extrinsics;
using Substrate.Gear.Client.NetApi.Model.Rpc;
using Substrate.Gear.Client.NetApi.Model.Types.Base;
Expand All @@ -27,6 +28,7 @@
using CodeChangedEventData = Substrate.NetApi.Model.Types.Base.BaseTuple<
Substrate.Gear.Api.Generated.Model.gprimitives.CodeId,
Substrate.Gear.Api.Generated.Model.gear_common.@event.EnumCodeChangeKind>;
using CodeId = Substrate.Gear.Api.Generated.Model.gprimitives.CodeId;
using EnumGearEvent = Substrate.Gear.Api.Generated.Model.pallet_gear.pallet.EnumEvent;
using EnumSystemEvent = Substrate.Gear.Api.Generated.Model.frame_system.pallet.EnumEvent;
using ExtrinsicFailedEventData = Substrate.NetApi.Model.Types.Base.BaseTuple<
Expand Down Expand Up @@ -340,6 +342,7 @@ public static async Task<GasInfo> CalculateGasForCreateProgramAsync(
EnsureArg.IsNotNull(encodedInitPayload, nameof(encodedInitPayload));

var accountPublicKeyStr = Utils.Bytes2HexString(signingAccountKey.Key);
var codeIdStr = codeId.ToHexString();
var encodedInitPayloadStr = Utils.Bytes2HexString(
encodedInitPayload is byte[] encodedInitPayloadBytes
? encodedInitPayloadBytes
Expand All @@ -348,7 +351,7 @@ encodedInitPayload is byte[] encodedInitPayloadBytes
var parameters = new object[]
{
accountPublicKeyStr,
codeId,
codeIdStr,
encodedInitPayloadStr,
valueBigInt,
true
Expand Down Expand Up @@ -438,14 +441,15 @@ public static async Task<GasInfo> CalculateGasForHandleAsync(
EnsureArg.IsNotNull(encodedPayload, nameof(encodedPayload));

var accountPublicKeyStr = Utils.Bytes2HexString(signingAccountKey.Key);
var programIdStr = programId.ToHexString();
var encodedPayloadStr = Utils.Bytes2HexString(
encodedPayload is byte[] encodedPayloadBytes
? encodedPayloadBytes
: [.. encodedPayload]);
var parameters = new object[]
{
accountPublicKeyStr,
programId,
programIdStr,
encodedPayloadStr,
value.Value,
true
Expand Down Expand Up @@ -487,14 +491,15 @@ public static async Task<ReplyInfo> CalculateReplyForHandleAsync(
EnsureArg.IsNotNull(encodedPayload, nameof(encodedPayload));

var accountPublicKeyStr = Utils.Bytes2HexString(signingAccountKey.Key);
var programIdStr = programId.ToHexString();
var encodedPayloadStr = Utils.Bytes2HexString(
encodedPayload is byte[] encodedPayloadBytes
? encodedPayloadBytes
: [.. encodedPayload]);
var parameters = new object[]
{
accountPublicKeyStr,
programId,
programIdStr,
encodedPayloadStr,
gasLimit.Value,
value.Value,
Expand Down Expand Up @@ -591,7 +596,7 @@ private sealed record ReplyInfoJson
{
// Payload of the reply.
[JsonProperty("payload")]
public required byte[] EncodedPayload { get; init; }
public required string EncodedPayload { get; init; }
// Value sent with the reply.
public BigInteger Value { get; init; }
// Reply code of the reply.
Expand All @@ -600,9 +605,9 @@ private sealed record ReplyInfoJson
public ReplyInfo ToReplyInfo()
=> new()
{
EncodedPayload = this.EncodedPayload,
EncodedPayload = Utils.HexToByteArray(this.EncodedPayload),
Value = (ValueUnit)this.Value,
// TODO: It is broken. Need to deserialize rust enum.
// TODO: It is broken. Need to deserialize rust enum (see serde).
Code = new EnumReplyCode()
{
Value = ReplyCode.Success
Expand Down
129 changes: 114 additions & 15 deletions net/tests/Sails.Remoting.Tests/Core/RemotingViaNodeClientTests.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Sails.Remoting.Tests._Infra.XUnit.Fixtures;
using Sails.Tests.Shared.XUnit;
using Sails.Remoting.Tests._Infra.XUnit.Fixtures;
using Substrate.Gear.Api.Generated;
using Substrate.Gear.Client;
using Substrate.Gear.Client.Extensions;
using Substrate.Gear.Client.GearApi.Model.gprimitives;
using Substrate.NET.Schnorrkel.Keys;
using Substrate.NetApi;
using Substrate.NetApi.Model.Extrinsics;
using Substrate.NetApi.Model.Types;
using Xunit;
using Substrate.NetApi.Model.Types.Primitive;
using CodeId = Substrate.Gear.Api.Generated.Model.gprimitives.CodeId;

namespace Sails.Remoting.Tests.Core;

Expand All @@ -19,6 +17,15 @@ public sealed class RemotingViaNodeClientTests : IAssemblyFixture<SailsFixture>
public RemotingViaNodeClientTests(SailsFixture sailsFixture)
{
this.sailsFixture = sailsFixture;
var serviceCollection = new ServiceCollection();
serviceCollection.AddRemotingViaNodeClient(
new NodeClientOptions
{
GearNodeUri = this.sailsFixture.GearNodeWsUrl,
});
var serviceProvider = serviceCollection.BuildServiceProvider();
this.remotingProvider = serviceProvider.GetRequiredService<IRemotingProvider>();
this.remoting = this.remotingProvider.CreateRemoting(AliceAccount);
}

private static readonly MiniSecret AliceMiniSecret
Expand All @@ -30,26 +37,118 @@ private static readonly Account AliceAccount
KeyType.Sr25519,
AliceMiniSecret.ExpandToSecret().ToEd25519Bytes(),
AliceMiniSecret.GetPair().Public.Key);
private static readonly Random Random = new((int)DateTime.UtcNow.Ticks);

private readonly SailsFixture sailsFixture;
private readonly IRemotingProvider remotingProvider;
private readonly IRemoting remoting;

[Fact]
public async Task Test()
public void Service_Provider_Resolves_Expected_Implementation()
=> this.remoting.Should().BeOfType<RemotingViaNodeClient>();

[Fact]
public async Task Program_Activation_Works()
{
// Arrange
var codeBytes = await this.sailsFixture.GetNoSvcsProgContractWasmAsync();
var codeId = await this.UploadCodeAsync(codeBytes.AsReadOnlyCollection());

// Act
var encodedPayload = new Str("Default").Encode();
var activationReply = await this.remoting.ActivateAsync(
codeId,
salt: BitConverter.GetBytes(Random.NextInt64()),
encodedPayload,
CancellationToken.None);

// Assert
var activationResult = await activationReply.ReadAsync(CancellationToken.None);

var programIdStr = activationResult.ProgramId.ToHexString(); // Should be asserted against logs produced by node

activationResult.Payload.Should().BeEquivalentTo(encodedPayload, options => options.WithStrictOrdering());
}

[Fact]
public async Task Sending_Message_To_Program_Works()
{
// Arrange
var codeBytes = await this.sailsFixture.GetDemoContractWasmAsync();
var codeId = await this.UploadCodeAsync(codeBytes.AsReadOnlyCollection());
var activationReply = await this.remoting.ActivateAsync(
codeId,
salt: BitConverter.GetBytes(Random.NextInt64()),
new Str("Default").Encode(),
CancellationToken.None);
var activationResult = await activationReply.ReadAsync(CancellationToken.None);

// Act
var encodedPayload = new Str("Counter").Encode()
.Concat(new Str("Add").Encode())
.Concat(new U32(42).Encode())
.ToArray();
var messageReply = await this.remoting.MessageAsync(
activationResult.ProgramId,
encodedPayload,
CancellationToken.None);

// Assert
var messageResult = await messageReply.ReadAsync(CancellationToken.None);

messageResult.Should().BeEquivalentTo(encodedPayload, options => options.WithStrictOrdering());

// Some assertion of programId and payload against logs produced by node
}

[Fact]
public async Task Querying_Program_State_Works()
{
var nodeWsUrl = this.sailsFixture.GearNodeWsUrl;
// Arrange
var codeBytes = await this.sailsFixture.GetDemoContractWasmAsync();
var codeId = await this.UploadCodeAsync(codeBytes.AsReadOnlyCollection());
var activationReply = await this.remoting.ActivateAsync(
codeId,
salt: BitConverter.GetBytes(Random.NextInt64()),
new Str("Default").Encode(),
CancellationToken.None);
var activationResult = await activationReply.ReadAsync(CancellationToken.None);
var messageReply = await this.remoting.MessageAsync(
activationResult.ProgramId,
encodedPayload: new Str("Counter").Encode()
.Concat(new Str("Add").Encode())
.Concat(new U32(42).Encode())
.ToArray(),
CancellationToken.None);
await messageReply.ReadAsync(CancellationToken.None);

using (var nodeClient = new SubstrateClientExt(nodeWsUrl, ChargeTransactionPayment.Default()))
// Act
var encodedPayload = new Str("Counter").Encode()
.Concat(new Str("Value").Encode())
.ToArray();
var queryResult = await this.remoting.QueryAsync(
activationResult.ProgramId,
encodedPayload,
CancellationToken.None);

// Assert
queryResult.Should().BeEquivalentTo(
encodedPayload.Concat(new U32(42).Encode()).ToArray(),
options => options.WithStrictOrdering());
}

private async Task<CodeId> UploadCodeAsync(IReadOnlyCollection<byte> codeBytes)
{
using (var nodeClient = new SubstrateClientExt(
this.sailsFixture.GearNodeWsUrl,
ChargeTransactionPayment.Default()))
{
await nodeClient.ConnectAsync();

var codeBytes = await this.sailsFixture.GetNoSvcsProgContractWasmAsync();

var codeId = await nodeClient.UploadCodeAsync(
return await nodeClient.UploadCodeAsync(
AliceAccount,
codeBytes.AsReadOnlyCollection(),
codeBytes,
CancellationToken.None);

var codeIdStr = Utils.Bytes2HexString(codeId.Value.Value.Select(b => b.Value).ToArray());
}
}
}
19 changes: 19 additions & 0 deletions net/tests/Sails.Remoting.Tests/GlobalUsings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
global using System;
global using System.Collections.Generic;
global using System.IO;
global using System.Linq;
global using System.Text.RegularExpressions;
global using System.Threading;
global using System.Threading.Tasks;
global using EnsureThat;
global using FluentAssertions;
global using Microsoft.Extensions.DependencyInjection;
global using Sails.Remoting.Abstractions.Core;
global using Sails.Remoting.Core;
global using Sails.Remoting.DependencyInjection;
global using Sails.Remoting.Options;
global using Sails.Tests.Shared.Containers;
global using Sails.Tests.Shared.Git;
global using Sails.Tests.Shared.XUnit;
global using Xunit;
global using Xunit.Abstractions;
2 changes: 2 additions & 0 deletions net/tests/Sails.Remoting.Tests/Sails.Remoting.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="FluentAssertions" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="Nito.AsyncEx" />
<PackageReference Include="xunit" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,5 @@
using EnsureThat;
using Nito.AsyncEx;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Threading;
using System;
using Nito.AsyncEx;
using Sails.Remoting.Tests._Infra.XUnit.Fixtures;
using Sails.Tests.Shared.Containers;
using Sails.Tests.Shared.Git;
using Sails.Tests.Shared.XUnit;
using Xunit;

[assembly: AssemblyFixture(typeof(SailsFixture))]

Expand Down
4 changes: 1 addition & 3 deletions net/tests/Sails.Remoting.Tests/_Infra/XUnit/TestFramework.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using Xunit.Abstractions;

[assembly: Xunit.TestFramework(
[assembly: TestFramework(
"Sails.Remoting.Tests._Infra.XUnit.TestFramework",
"Sails.Remoting.Tests")]

Expand Down

0 comments on commit 98e0325

Please sign in to comment.