From dcd00d01927491e66e70b4c6fbbef8390de17562 Mon Sep 17 00:00:00 2001 From: Dennis Dyatlov Date: Mon, 25 Nov 2024 13:44:22 +0000 Subject: [PATCH 1/7] [net]refactor(tests): refactor tests infrastructure and add Sails.DemoClient project --- Sails.Net.sln | 16 ++ net/Directory.Packages.props | 10 +- .../Sails.DemoClient/Sails.DemoClient.csproj | 16 ++ net/examples/Sails.DemoClient/demo.idl | 91 +++++++ .../AssemblyAttributes.cs | 9 + .../DemoFactoryTests.cs | 24 ++ .../Sails.DemoClient.Tests.csproj | 22 ++ .../AssemblyAttributes.cs | 6 + .../Core/RemotingViaNodeClientTests.cs | 63 ++--- .../Sails.Remoting.Tests/GlobalUsings.cs | 6 - .../Sails.Remoting.Tests.csproj | 6 - .../_Infra/XUnit/Fixtures/SailsFixture.cs | 138 ----------- .../_Infra/XUnit/TestFramework.cs | 13 - .../Containers/GearNodeContainer.cs | 8 +- .../Sails.Tests.Shared.csproj | 6 + .../XUnit/Fixtures/SailsFixture.cs | 226 ++++++++++++++++++ .../XUnit/TestAssemblyRunner.cs | 4 +- .../Sails.Tests.Shared/XUnit/TestFramework.cs | 4 +- .../XUnit/TestFrameworkExecutor.cs | 6 +- nuget.config | 15 ++ 20 files changed, 465 insertions(+), 224 deletions(-) create mode 100644 net/examples/Sails.DemoClient/Sails.DemoClient.csproj create mode 100644 net/examples/Sails.DemoClient/demo.idl create mode 100644 net/tests/Sails.DemoClient.Tests/AssemblyAttributes.cs create mode 100644 net/tests/Sails.DemoClient.Tests/DemoFactoryTests.cs create mode 100644 net/tests/Sails.DemoClient.Tests/Sails.DemoClient.Tests.csproj create mode 100644 net/tests/Sails.Remoting.Tests/AssemblyAttributes.cs delete mode 100644 net/tests/Sails.Remoting.Tests/_Infra/XUnit/Fixtures/SailsFixture.cs delete mode 100644 net/tests/Sails.Remoting.Tests/_Infra/XUnit/TestFramework.cs create mode 100644 net/tests/Sails.Tests.Shared/XUnit/Fixtures/SailsFixture.cs create mode 100644 nuget.config diff --git a/Sails.Net.sln b/Sails.Net.sln index ba363611..7cf30a1d 100644 --- a/Sails.Net.sln +++ b/Sails.Net.sln @@ -33,6 +33,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Substrate.Gear.Client.Tests EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sails.Client.Tests", "net\tests\Sails.Client.Tests\Sails.Client.Tests.csproj", "{BC248D44-14CD-4BB0-9AF9-4E0750574492}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{4D457454-ED79-4BC3-8B6B-AC6934AAF048}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sails.DemoClient", "net\examples\Sails.DemoClient\Sails.DemoClient.csproj", "{C9D87AD3-612B-43A0-89BD-9211FE2FB310}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sails.DemoClient.Tests", "net\tests\Sails.DemoClient.Tests\Sails.DemoClient.Tests.csproj", "{5ED8CDB7-F896-4ACE-8B7B-A128CCBBCFA4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -83,6 +89,14 @@ Global {BC248D44-14CD-4BB0-9AF9-4E0750574492}.Debug|Any CPU.Build.0 = Debug|Any CPU {BC248D44-14CD-4BB0-9AF9-4E0750574492}.Release|Any CPU.ActiveCfg = Release|Any CPU {BC248D44-14CD-4BB0-9AF9-4E0750574492}.Release|Any CPU.Build.0 = Release|Any CPU + {C9D87AD3-612B-43A0-89BD-9211FE2FB310}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C9D87AD3-612B-43A0-89BD-9211FE2FB310}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C9D87AD3-612B-43A0-89BD-9211FE2FB310}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C9D87AD3-612B-43A0-89BD-9211FE2FB310}.Release|Any CPU.Build.0 = Release|Any CPU + {5ED8CDB7-F896-4ACE-8B7B-A128CCBBCFA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5ED8CDB7-F896-4ACE-8B7B-A128CCBBCFA4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5ED8CDB7-F896-4ACE-8B7B-A128CCBBCFA4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5ED8CDB7-F896-4ACE-8B7B-A128CCBBCFA4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -93,6 +107,8 @@ Global {A6A2172B-8F8F-4BDC-B519-E7299FFCCA5F} = {19594BCA-94DB-44AD-ACBC-2ACFED242E9F} {42B621CE-C2B4-4911-961C-5B087A514AF5} = {19594BCA-94DB-44AD-ACBC-2ACFED242E9F} {BC248D44-14CD-4BB0-9AF9-4E0750574492} = {19594BCA-94DB-44AD-ACBC-2ACFED242E9F} + {C9D87AD3-612B-43A0-89BD-9211FE2FB310} = {4D457454-ED79-4BC3-8B6B-AC6934AAF048} + {5ED8CDB7-F896-4ACE-8B7B-A128CCBBCFA4} = {19594BCA-94DB-44AD-ACBC-2ACFED242E9F} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {0894C08B-8BB9-401D-8471-26F5EB5A4EA2} diff --git a/net/Directory.Packages.props b/net/Directory.Packages.props index 17b57a68..c5b61101 100644 --- a/net/Directory.Packages.props +++ b/net/Directory.Packages.props @@ -11,7 +11,7 @@ - + @@ -19,17 +19,21 @@ + - + - + + + + diff --git a/net/examples/Sails.DemoClient/Sails.DemoClient.csproj b/net/examples/Sails.DemoClient/Sails.DemoClient.csproj new file mode 100644 index 00000000..3e49ccb2 --- /dev/null +++ b/net/examples/Sails.DemoClient/Sails.DemoClient.csproj @@ -0,0 +1,16 @@ + + + + netstandard2.0 + + + + + + + + + + + + diff --git a/net/examples/Sails.DemoClient/demo.idl b/net/examples/Sails.DemoClient/demo.idl new file mode 100644 index 00000000..d7cc6728 --- /dev/null +++ b/net/examples/Sails.DemoClient/demo.idl @@ -0,0 +1,91 @@ +type ReferenceCount = struct { + u32, +}; + +type DoThatParam = struct { + p1: nat32, + p2: actor_id, + p3: ManyVariants, +}; + +type ManyVariants = enum { + One, + Two: u32, + Three: opt u256, + Four: struct { a: u32, b: opt u16 }, + Five: struct { str, h256 }, + Six: struct { u32 }, +}; + +type TupleStruct = struct { + bool, +}; + +constructor { + /// Program constructor (called once at the very beginning of the program lifetime) + Default : (); + /// Another program constructor (called once at the very beginning of the program lifetime) + New : (counter: opt u32, dog_position: opt struct { i32, i32 }); +}; + +service Counter { + /// Add a value to the counter + Add : (value: u32) -> u32; + /// Substract a value from the counter + Sub : (value: u32) -> u32; + /// Get the current value + query Value : () -> u32; + + events { + /// Emitted when a new value is added to the counter + Added: u32; + /// Emitted when a value is subtracted from the counter + Subtracted: u32; + } +}; + +service Dog { + MakeSound : () -> str; + Walk : (dx: i32, dy: i32) -> null; + query AvgWeight : () -> u32; + query Position : () -> struct { i32, i32 }; + + events { + Barked; + Walked: struct { from: struct { i32, i32 }, to: struct { i32, i32 } }; + } +}; + +service PingPong { + Ping : (input: str) -> result (str, str); +}; + +service References { + Add : (v: u32) -> u32; + AddByte : (byte: u8) -> vec u8; + GuessNum : (number: u8) -> result (str, str); + Incr : () -> ReferenceCount; + SetNum : (number: u8) -> result (null, str); + query Baked : () -> str; + query LastByte : () -> opt u8; + query Message : () -> opt str; +}; + +service ThisThat { + DoThat : (param: DoThatParam) -> result (struct { actor_id, nat32 }, struct { str }); + DoThis : (p1: u32, p2: str, p3: struct { opt h160, nat8 }, p4: TupleStruct) -> struct { str, u32 }; + Noop : () -> null; + query That : () -> result (str, str); + query This : () -> u32; +}; + +service ValueFee { + /// Return flag if fee taken and remain value, + /// using special type `CommandReply` + DoSomethingAndTakeFee : () -> bool; + + events { + Withheld: u128; + } +}; + diff --git a/net/tests/Sails.DemoClient.Tests/AssemblyAttributes.cs b/net/tests/Sails.DemoClient.Tests/AssemblyAttributes.cs new file mode 100644 index 00000000..a365ad10 --- /dev/null +++ b/net/tests/Sails.DemoClient.Tests/AssemblyAttributes.cs @@ -0,0 +1,9 @@ +using Sails.Tests.Shared.XUnit; +using Xunit; + +[assembly: TestFramework( + "Sails.Tests.Shared.XUnit.TestFramework", + "Sails.Tests.Shared")] + +[assembly: AssemblyFixture( + typeof(Sails.Tests.Shared.XUnit.Fixtures.SailsFixture))] diff --git a/net/tests/Sails.DemoClient.Tests/DemoFactoryTests.cs b/net/tests/Sails.DemoClient.Tests/DemoFactoryTests.cs new file mode 100644 index 00000000..b0c640fd --- /dev/null +++ b/net/tests/Sails.DemoClient.Tests/DemoFactoryTests.cs @@ -0,0 +1,24 @@ +using System.Threading.Tasks; +using Sails.Tests.Shared.XUnit; +using Sails.Tests.Shared.XUnit.Fixtures; +using Xunit; + +namespace Sails.DemoClient.Tests; + +public sealed class DemoFactoryTests : IAssemblyFixture +{ + public DemoFactoryTests(SailsFixture fixture) + { + this.sailsFixture = fixture; + // Assert that IDL file from the Sails.DemoClient project is the same as the one + // from the SailsFixture + } + + private readonly SailsFixture sailsFixture; + + [Fact] + public async Task Test1() + { + var demoContractCodeId = await this.sailsFixture.GetDemoContractCodeIdAsync(); + } +} diff --git a/net/tests/Sails.DemoClient.Tests/Sails.DemoClient.Tests.csproj b/net/tests/Sails.DemoClient.Tests/Sails.DemoClient.Tests.csproj new file mode 100644 index 00000000..eeb8d95e --- /dev/null +++ b/net/tests/Sails.DemoClient.Tests/Sails.DemoClient.Tests.csproj @@ -0,0 +1,22 @@ + + + + net8.0 + false + true + $(NoWarn);xUnit1041 + + + + + + + + + + + + + + + diff --git a/net/tests/Sails.Remoting.Tests/AssemblyAttributes.cs b/net/tests/Sails.Remoting.Tests/AssemblyAttributes.cs new file mode 100644 index 00000000..867a9faf --- /dev/null +++ b/net/tests/Sails.Remoting.Tests/AssemblyAttributes.cs @@ -0,0 +1,6 @@ +[assembly: TestFramework( + "Sails.Tests.Shared.XUnit.TestFramework", + "Sails.Tests.Shared")] + +[assembly: AssemblyFixture( + typeof(Sails.Tests.Shared.XUnit.Fixtures.SailsFixture))] diff --git a/net/tests/Sails.Remoting.Tests/Core/RemotingViaNodeClientTests.cs b/net/tests/Sails.Remoting.Tests/Core/RemotingViaNodeClientTests.cs index 3f603faf..b390a0ce 100644 --- a/net/tests/Sails.Remoting.Tests/Core/RemotingViaNodeClientTests.cs +++ b/net/tests/Sails.Remoting.Tests/Core/RemotingViaNodeClientTests.cs @@ -1,14 +1,6 @@ -using Sails.Remoting.Tests._Infra.XUnit.Fixtures; -using Substrate.Gear.Api.Generated; -using Substrate.Gear.Client; -using Substrate.Gear.Client.Extensions; +using Sails.Tests.Shared.XUnit.Fixtures; 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 Substrate.NetApi.Model.Types.Primitive; -using CodeId = Substrate.Gear.Api.Generated.Model.gprimitives.CodeId; namespace Sails.Remoting.Tests.Core; @@ -25,18 +17,9 @@ public RemotingViaNodeClientTests(SailsFixture sailsFixture) }); var serviceProvider = serviceCollection.BuildServiceProvider(); this.remotingProvider = serviceProvider.GetRequiredService(); - this.remoting = this.remotingProvider.CreateRemoting(AliceAccount); + this.remoting = this.remotingProvider.CreateRemoting(SailsFixture.AliceAccount); } - private static readonly MiniSecret AliceMiniSecret - = new( - Utils.HexToByteArray("0xe5be9a5092b81bca64be81d212e7f2f9eba183bb7a90954f7b76361f6edb5c0a"), - ExpandMode.Ed25519); - private static readonly Account AliceAccount - = Account.Build( - KeyType.Sr25519, - AliceMiniSecret.ExpandToSecret().ToEd25519Bytes(), - AliceMiniSecret.GetPair().Public.Key); private static readonly Random Random = new((int)DateTime.UtcNow.Ticks); private readonly SailsFixture sailsFixture; @@ -51,8 +34,7 @@ public void Service_Provider_Resolves_Expected_Implementation() public async Task Program_Activation_Works() { // Arrange - var codeBytes = await this.sailsFixture.GetNoSvcsProgContractWasmAsync(); - var codeId = await this.UploadCodeAsync(codeBytes.AsReadOnlyCollection()); + var codeId = await this.sailsFixture.GetDemoContractCodeIdAsync(); // Act var encodedPayload = new Str("Default").Encode(); @@ -63,25 +45,24 @@ public async Task Program_Activation_Works() CancellationToken.None); // Assert - var activationResult = await activationReply.ReadAsync(CancellationToken.None); + var (programId, payload) = await activationReply.ReadAsync(CancellationToken.None); - var programIdStr = activationResult.ProgramId.ToHexString(); // Should be asserted against logs produced by node + var programIdStr = programId.ToHexString(); // Should be asserted against logs produced by node - activationResult.Payload.Should().BeEquivalentTo(encodedPayload, options => options.WithStrictOrdering()); + 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 codeId = await this.sailsFixture.GetDemoContractCodeIdAsync(); 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 (programId, _) = await activationReply.ReadAsync(CancellationToken.None); // Act var encodedPayload = new Str("Counter").Encode() @@ -89,7 +70,7 @@ public async Task Sending_Message_To_Program_Works() .Concat(new U32(42).Encode()) .ToArray(); var messageReply = await this.remoting.MessageAsync( - activationResult.ProgramId, + programId, encodedPayload, CancellationToken.None); @@ -105,16 +86,15 @@ public async Task Sending_Message_To_Program_Works() public async Task Querying_Program_State_Works() { // Arrange - var codeBytes = await this.sailsFixture.GetDemoContractWasmAsync(); - var codeId = await this.UploadCodeAsync(codeBytes.AsReadOnlyCollection()); + var codeId = await this.sailsFixture.GetDemoContractCodeIdAsync(); 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 (programId, _) = await activationReply.ReadAsync(CancellationToken.None); var messageReply = await this.remoting.MessageAsync( - activationResult.ProgramId, + programId, encodedPayload: new Str("Counter").Encode() .Concat(new Str("Add").Encode()) .Concat(new U32(42).Encode()) @@ -127,28 +107,13 @@ public async Task Querying_Program_State_Works() .Concat(new Str("Value").Encode()) .ToArray(); var queryResult = await this.remoting.QueryAsync( - activationResult.ProgramId, + programId, encodedPayload, CancellationToken.None); // Assert queryResult.Should().BeEquivalentTo( - encodedPayload.Concat(new U32(42).Encode()).ToArray(), + [.. encodedPayload, .. new U32(42).Encode()], options => options.WithStrictOrdering()); } - - private async Task UploadCodeAsync(IReadOnlyCollection codeBytes) - { - using (var nodeClient = new SubstrateClientExt( - this.sailsFixture.GearNodeWsUrl, - ChargeTransactionPayment.Default())) - { - await nodeClient.ConnectAsync(); - - return await nodeClient.UploadCodeAsync( - AliceAccount, - codeBytes, - CancellationToken.None); - } - } } diff --git a/net/tests/Sails.Remoting.Tests/GlobalUsings.cs b/net/tests/Sails.Remoting.Tests/GlobalUsings.cs index d22948a8..65d06e66 100644 --- a/net/tests/Sails.Remoting.Tests/GlobalUsings.cs +++ b/net/tests/Sails.Remoting.Tests/GlobalUsings.cs @@ -1,19 +1,13 @@ 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; diff --git a/net/tests/Sails.Remoting.Tests/Sails.Remoting.Tests.csproj b/net/tests/Sails.Remoting.Tests/Sails.Remoting.Tests.csproj index bf619d93..a940f93f 100644 --- a/net/tests/Sails.Remoting.Tests/Sails.Remoting.Tests.csproj +++ b/net/tests/Sails.Remoting.Tests/Sails.Remoting.Tests.csproj @@ -15,7 +15,6 @@ - all @@ -24,11 +23,6 @@ - - diff --git a/net/tests/Sails.Remoting.Tests/_Infra/XUnit/Fixtures/SailsFixture.cs b/net/tests/Sails.Remoting.Tests/_Infra/XUnit/Fixtures/SailsFixture.cs deleted file mode 100644 index 0fa13585..00000000 --- a/net/tests/Sails.Remoting.Tests/_Infra/XUnit/Fixtures/SailsFixture.cs +++ /dev/null @@ -1,138 +0,0 @@ -using Nito.AsyncEx; -using Sails.Remoting.Tests._Infra.XUnit.Fixtures; - -[assembly: AssemblyFixture(typeof(SailsFixture))] - -namespace Sails.Remoting.Tests._Infra.XUnit.Fixtures; - -public sealed partial class SailsFixture : IAsyncLifetime -{ - public SailsFixture() - : this(sailsRsVersion: "0.6.3") - { - } - - public SailsFixture(string sailsRsVersion) - { - EnsureArg.IsNotNullOrWhiteSpace(sailsRsVersion, nameof(sailsRsVersion)); - - this.sailsRsReleaseTag = $"rs/v{sailsRsVersion}"; - this.demoContractIdl = new AsyncLazy( - () => this.DownloadStringAsset("demo.idl"), - AsyncLazyFlags.RetryOnFailure); - this.demoContractWasm = new AsyncLazy( - () => this.DownloadOctetAsset("demo.wasm"), - AsyncLazyFlags.RetryOnFailure); - this.noSvcsProgContractIdl = new AsyncLazy( - () => this.DownloadStringAsset("no-svcs-prog.idl"), - AsyncLazyFlags.RetryOnFailure); - this.noSvcsProgContractWasm = new AsyncLazy( - () => this.DownloadOctetAsset("no_svcs_prog.wasm"), - AsyncLazyFlags.RetryOnFailure); - this.gearNodeContainer = null; - } - - private static readonly GithubDownloader GithubDownloader = new("gear-tech", "sails"); - - private readonly string sailsRsReleaseTag; - private readonly AsyncLazy demoContractIdl; - private readonly AsyncLazy demoContractWasm; - private readonly AsyncLazy noSvcsProgContractIdl; - private readonly AsyncLazy noSvcsProgContractWasm; - private GearNodeContainer? gearNodeContainer; - - public Uri GearNodeWsUrl => this.gearNodeContainer?.WsUrl - ?? throw new InvalidOperationException("Gear node container is not initialized."); - - public async Task DisposeAsync() - { - if (this.gearNodeContainer is not null) - { - await this.gearNodeContainer.DisposeAsync(); - this.gearNodeContainer = null; - } - if (this.demoContractWasm.IsStarted) - { - await (await this.demoContractWasm).DisposeAsync(); - } - if (this.noSvcsProgContractWasm.IsStarted) - { - await (await this.noSvcsProgContractWasm).DisposeAsync(); - } - } - - public async Task InitializeAsync() - { - var sailsRsCargoToml = await this.DownloadSailsRsCargoTomlAsync(); - - var matchResult = GStdDependencyRegex().Match(sailsRsCargoToml); - if (!matchResult.Success) - { - throw new InvalidOperationException( - $"Failed to find gstd dependency in Cargo.toml by the '{this.sailsRsReleaseTag}' tag."); - } - var gearNodeVersion = matchResult.Groups[1].Value; - - // The `reuse` parameter can be made configurable if needed - this.gearNodeContainer = new GearNodeContainer(gearNodeVersion, reuse: true); - await this.gearNodeContainer.StartAsync(); - } - - public Task GetDemoContractIdlAsync() - => this.demoContractIdl.Task; - - public async Task> GetDemoContractWasmAsync() - { - var byteStream = await this.demoContractWasm; - Ensure.Comparable.IsLte(byteStream.Length, int.MaxValue); - return new ReadOnlyMemory(byteStream.GetBuffer(), start: 0, length: (int)byteStream.Length); - } - - public Task GetNoSvcsProgContractIdlAsync() - => this.noSvcsProgContractIdl.Task; - - public async Task> GetNoSvcsProgContractWasmAsync() - { - var byteStream = await this.noSvcsProgContractWasm; - Ensure.Comparable.IsLte(byteStream.Length, int.MaxValue); - return new ReadOnlyMemory(byteStream.GetBuffer(), start: 0, length: (int)byteStream.Length); - } - - private async Task DownloadStringAsset(string assetName) - { - var downloadStream = await GithubDownloader.DownloadReleaseAssetAsync( - this.sailsRsReleaseTag, - assetName, - CancellationToken.None); - using (var reader = new StreamReader(downloadStream, leaveOpen: false)) - { - return await reader.ReadToEndAsync(CancellationToken.None); - } - } - - private async Task DownloadOctetAsset(string assetName) - { - var downloadStream = await GithubDownloader.DownloadReleaseAssetAsync( - this.sailsRsReleaseTag, - assetName, - CancellationToken.None); - var memoryStream = new MemoryStream(); - await downloadStream.CopyToAsync(memoryStream); - return memoryStream; - } - - private async Task DownloadSailsRsCargoTomlAsync() - { - var downloadStream = await GithubDownloader.DownloadFileFromTagAsync( - this.sailsRsReleaseTag, - "Cargo.toml", - CancellationToken.None); - using (var reader = new StreamReader(downloadStream, leaveOpen: false)) - { - return await reader.ReadToEndAsync(CancellationToken.None); - } - } - - [GeneratedRegex(@"gstd\s*=\s*""=?(\d+\.\d+\.\d+)""")] - private static partial Regex GStdDependencyRegex(); -} diff --git a/net/tests/Sails.Remoting.Tests/_Infra/XUnit/TestFramework.cs b/net/tests/Sails.Remoting.Tests/_Infra/XUnit/TestFramework.cs deleted file mode 100644 index 3580ce24..00000000 --- a/net/tests/Sails.Remoting.Tests/_Infra/XUnit/TestFramework.cs +++ /dev/null @@ -1,13 +0,0 @@ -[assembly: TestFramework( - "Sails.Remoting.Tests._Infra.XUnit.TestFramework", - "Sails.Remoting.Tests")] - -namespace Sails.Remoting.Tests._Infra.XUnit; - -internal sealed class TestFramework : Sails.Tests.Shared.XUnit.TestFramework -{ - public TestFramework(IMessageSink messageSink) - : base(messageSink) - { - } -} diff --git a/net/tests/Sails.Tests.Shared/Containers/GearNodeContainer.cs b/net/tests/Sails.Tests.Shared/Containers/GearNodeContainer.cs index 8205d792..277d8773 100644 --- a/net/tests/Sails.Tests.Shared/Containers/GearNodeContainer.cs +++ b/net/tests/Sails.Tests.Shared/Containers/GearNodeContainer.cs @@ -57,8 +57,8 @@ public ValueTask DisposeAsync() public async Task StartAsync() { - await this.container.StartAsync(); - await this.nodeInitializationDetector.IsInitializedAsync(NodeInitializationTimeout); + await this.container.StartAsync().ConfigureAwait(false); + await this.nodeInitializationDetector.IsInitializedAsync(NodeInitializationTimeout).ConfigureAwait(false); } private sealed class NodeInitializationDetector : IOutputConsumer @@ -81,12 +81,12 @@ public NodeInitializationDetector() public async Task IsInitializedAsync(TimeSpan maxWaitTime) { var timeoutTask = Task.Delay(maxWaitTime); - var completedTask = await Task.WhenAny(this.isNodeInitialized.Task, timeoutTask); + var completedTask = await Task.WhenAny(this.isNodeInitialized.Task, timeoutTask).ConfigureAwait(false); if (completedTask == timeoutTask) { this.isNodeInitialized.SetException( new TimeoutException($"Node initialization timed out after {maxWaitTime}.")); - await this.isNodeInitialized.Task; + await this.isNodeInitialized.Task.ConfigureAwait(false); } } diff --git a/net/tests/Sails.Tests.Shared/Sails.Tests.Shared.csproj b/net/tests/Sails.Tests.Shared/Sails.Tests.Shared.csproj index bf5ab517..2df2bbc5 100644 --- a/net/tests/Sails.Tests.Shared/Sails.Tests.Shared.csproj +++ b/net/tests/Sails.Tests.Shared/Sails.Tests.Shared.csproj @@ -8,8 +8,14 @@ + + + + + + diff --git a/net/tests/Sails.Tests.Shared/XUnit/Fixtures/SailsFixture.cs b/net/tests/Sails.Tests.Shared/XUnit/Fixtures/SailsFixture.cs new file mode 100644 index 00000000..157541fe --- /dev/null +++ b/net/tests/Sails.Tests.Shared/XUnit/Fixtures/SailsFixture.cs @@ -0,0 +1,226 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using EnsureThat; +using Nito.AsyncEx; +using Polly; +using Polly.Retry; +using Sails.Tests.Shared.Containers; +using Sails.Tests.Shared.Git; +using Substrate.Gear.Api.Generated; +using Substrate.Gear.Api.Generated.Model.gprimitives; +using Substrate.Gear.Client; +using Substrate.NET.Schnorrkel.Keys; +using Substrate.NetApi; +using Substrate.NetApi.Model.Extrinsics; +using Substrate.NetApi.Model.Types; +using Xunit; + +namespace Sails.Tests.Shared.XUnit.Fixtures; + +public partial class SailsFixture : IAsyncLifetime +{ + public SailsFixture() + : this(sailsRsVersion: "0.6.3") + { + } + + public SailsFixture(string sailsRsVersion) + { + EnsureArg.IsNotNullOrWhiteSpace(sailsRsVersion, nameof(sailsRsVersion)); + + this.sailsRsReleaseTag = $"rs/v{sailsRsVersion}"; + this.demoContractIdl = new AsyncLazy( + () => this.DownloadStringAssetAsync("demo.idl"), + AsyncLazyFlags.RetryOnFailure); + this.demoContractWasm = new AsyncLazy( + () => this.DownloadOctetAssetAsync("demo.wasm"), + AsyncLazyFlags.RetryOnFailure); + this.demoContractCodeId = new AsyncLazy( + async () => + { + var codeBytes = await this.GetDemoContractWasmAsync().ConfigureAwait(false); + return await UploadCodeRetryPolicy.ExecuteAsync( + () => this.UploadCodeAsync(codeBytes.ToArray())) + .ConfigureAwait(false); + }, + AsyncLazyFlags.RetryOnFailure); + this.noSvcsProgContractIdl = new AsyncLazy( + () => this.DownloadStringAssetAsync("no-svcs-prog.idl"), + AsyncLazyFlags.RetryOnFailure); + this.noSvcsProgContractWasm = new AsyncLazy( + () => this.DownloadOctetAssetAsync("no_svcs_prog.wasm"), + AsyncLazyFlags.RetryOnFailure); + this.noSvcsProgContractCodeId = new AsyncLazy( + async () => + { + var codeBytes = await this.GetNoSvcsProgContractWasmAsync().ConfigureAwait(false); + return await UploadCodeRetryPolicy.ExecuteAsync( + () => this.UploadCodeAsync(codeBytes.ToArray())) + .ConfigureAwait(false); + }, + AsyncLazyFlags.RetryOnFailure); + this.gearNodeContainer = null; + } + + private static readonly GithubDownloader GithubDownloader = new("gear-tech", "sails"); + private static readonly AsyncRetryPolicy UploadCodeRetryPolicy = Policy.Handle( + exception => + exception.ErrorCode == 1014 && exception.Message.StartsWith("Priority is too low")) + .WaitAndRetryAsync( + 10, + retry => retry * TimeSpan.FromSeconds(1)); + + private readonly string sailsRsReleaseTag; + private readonly AsyncLazy demoContractIdl; + private readonly AsyncLazy demoContractWasm; + private readonly AsyncLazy demoContractCodeId; + private readonly AsyncLazy noSvcsProgContractIdl; + private readonly AsyncLazy noSvcsProgContractWasm; + private readonly AsyncLazy noSvcsProgContractCodeId; + private GearNodeContainer? gearNodeContainer; + + public static MiniSecret AliceMiniSecret { get; } + = new( + // Taken from 'gear key inspect //Alice' output + Utils.HexToByteArray("0xe5be9a5092b81bca64be81d212e7f2f9eba183bb7a90954f7b76361f6edb5c0a"), + ExpandMode.Ed25519); + public static Account AliceAccount { get; } + = Account.Build( + KeyType.Sr25519, + AliceMiniSecret.ExpandToSecret().ToEd25519Bytes(), + AliceMiniSecret.GetPair().Public.Key); + public static MiniSecret BobMiniSecret { get; } + = new( + // Taken from 'gear key inspect //Bob' output + Utils.HexToByteArray("0x398f0c28f98885e046333d4a41c19cee4c37368a9832c6502f6cfd182e2aef89"), + ExpandMode.Ed25519); + public static Account BobAccount { get; } + = Account.Build( + KeyType.Sr25519, + BobMiniSecret.ExpandToSecret().ToEd25519Bytes(), + BobMiniSecret.GetPair().Public.Key); + + public Uri GearNodeWsUrl => this.gearNodeContainer?.WsUrl + ?? throw new InvalidOperationException("Gear node container is not initialized."); + + public async Task DisposeAsync() + { + if (this.gearNodeContainer is not null) + { + await this.gearNodeContainer.DisposeAsync().ConfigureAwait(false); + this.gearNodeContainer = null; + } + if (this.demoContractWasm.IsStarted) + { + await (await this.demoContractWasm).DisposeAsync().ConfigureAwait(false); + } + if (this.noSvcsProgContractWasm.IsStarted) + { + await (await this.noSvcsProgContractWasm).DisposeAsync().ConfigureAwait(false); + } + } + + public async Task InitializeAsync() + { + var sailsRsCargoToml = await this.DownloadSailsRsCargoTomlAsync().ConfigureAwait(false); + + var matchResult = GStdDependencyRegex().Match(sailsRsCargoToml); + if (!matchResult.Success) + { + throw new InvalidOperationException( + $"Failed to find gstd dependency in Cargo.toml by the '{this.sailsRsReleaseTag}' tag."); + } + var gearNodeVersion = matchResult.Groups[1].Value; + + // The `reuse` parameter can be made configurable if needed + this.gearNodeContainer = new GearNodeContainer(gearNodeVersion, reuse: true); + await this.gearNodeContainer.StartAsync().ConfigureAwait(false); + } + + public Task GetDemoContractIdlAsync() + => this.demoContractIdl.Task; + + public async Task> GetDemoContractWasmAsync() + { + var byteStream = await this.demoContractWasm; + Ensure.Comparable.IsLte(byteStream.Length, int.MaxValue); + return new ReadOnlyMemory(byteStream.GetBuffer(), start: 0, length: (int)byteStream.Length); + } + + public Task GetDemoContractCodeIdAsync() + => this.demoContractCodeId.Task; + + public Task GetNoSvcsProgContractIdlAsync() + => this.noSvcsProgContractIdl.Task; + + public async Task> GetNoSvcsProgContractWasmAsync() + { + var byteStream = await this.noSvcsProgContractWasm; + Ensure.Comparable.IsLte(byteStream.Length, int.MaxValue); + return new ReadOnlyMemory(byteStream.GetBuffer(), start: 0, length: (int)byteStream.Length); + } + + public Task GetNoSvcsProgContractCodeIdAsync() + => this.noSvcsProgContractCodeId.Task; + + private async Task DownloadStringAssetAsync(string assetName) + { + var downloadStream = await GithubDownloader.DownloadReleaseAssetAsync( + this.sailsRsReleaseTag, + assetName, + CancellationToken.None) + .ConfigureAwait(false); + using (var reader = new StreamReader(downloadStream, leaveOpen: false)) + { + return await reader.ReadToEndAsync(CancellationToken.None).ConfigureAwait(false); + } + } + + private async Task DownloadOctetAssetAsync(string assetName) + { + var downloadStream = await GithubDownloader.DownloadReleaseAssetAsync( + this.sailsRsReleaseTag, + assetName, + CancellationToken.None) + .ConfigureAwait(false); + var memoryStream = new MemoryStream(); + await downloadStream.CopyToAsync(memoryStream).ConfigureAwait(false); + return memoryStream; + } + + private async Task DownloadSailsRsCargoTomlAsync() + { + var downloadStream = await GithubDownloader.DownloadFileFromTagAsync( + this.sailsRsReleaseTag, + "Cargo.toml", + CancellationToken.None) + .ConfigureAwait(false); + using (var reader = new StreamReader(downloadStream, leaveOpen: false)) + { + return await reader.ReadToEndAsync(CancellationToken.None).ConfigureAwait(false); + } + } + + private async Task UploadCodeAsync(IReadOnlyCollection codeBytes) + { + using (var nodeClient = new SubstrateClientExt( + this.GearNodeWsUrl, + ChargeTransactionPayment.Default())) + { + await nodeClient.ConnectAsync().ConfigureAwait(false); + + return await nodeClient.UploadCodeAsync( + AliceAccount, + codeBytes, + CancellationToken.None) + .ConfigureAwait(false); + } + } + + [GeneratedRegex(@"gstd\s*=\s*""=?(\d+\.\d+\.\d+)""")] + private static partial Regex GStdDependencyRegex(); +} diff --git a/net/tests/Sails.Tests.Shared/XUnit/TestAssemblyRunner.cs b/net/tests/Sails.Tests.Shared/XUnit/TestAssemblyRunner.cs index 90f4521a..90abc75b 100644 --- a/net/tests/Sails.Tests.Shared/XUnit/TestAssemblyRunner.cs +++ b/net/tests/Sails.Tests.Shared/XUnit/TestAssemblyRunner.cs @@ -30,7 +30,7 @@ public TestAssemblyRunner( protected override async Task AfterTestAssemblyStartingAsync() { - await base.AfterTestAssemblyStartingAsync(); + await base.AfterTestAssemblyStartingAsync().ConfigureAwait(false); var requiredFixtureTypes = new HashSet(); @@ -71,7 +71,7 @@ protected override async Task AfterTestAssemblyStartingAsync() foreach (var initializable in this.assemblyFixtureMappings.Values.OfType()) { - await this.Aggregator.RunAsync(initializable.InitializeAsync); + await this.Aggregator.RunAsync(initializable.InitializeAsync).ConfigureAwait(false); } } diff --git a/net/tests/Sails.Tests.Shared/XUnit/TestFramework.cs b/net/tests/Sails.Tests.Shared/XUnit/TestFramework.cs index 18820c25..13956cfb 100644 --- a/net/tests/Sails.Tests.Shared/XUnit/TestFramework.cs +++ b/net/tests/Sails.Tests.Shared/XUnit/TestFramework.cs @@ -4,9 +4,9 @@ namespace Sails.Tests.Shared.XUnit; -public abstract class TestFramework : XunitTestFramework +public class TestFramework : XunitTestFramework { - protected TestFramework(IMessageSink messageSink) + public TestFramework(IMessageSink messageSink) : base(messageSink) { } diff --git a/net/tests/Sails.Tests.Shared/XUnit/TestFrameworkExecutor.cs b/net/tests/Sails.Tests.Shared/XUnit/TestFrameworkExecutor.cs index be9079e6..55a424ce 100644 --- a/net/tests/Sails.Tests.Shared/XUnit/TestFrameworkExecutor.cs +++ b/net/tests/Sails.Tests.Shared/XUnit/TestFrameworkExecutor.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using Xunit.Abstractions; using Xunit.Sdk; @@ -15,6 +16,9 @@ public TestFrameworkExecutor( { } + [SuppressMessage( + "Usage", "VSTHRD100:Avoid async void methods", + Justification = "All exceptions should be added into the aggregator")] protected override async void RunTestCases( IEnumerable testCases, IMessageSink executionMessageSink, @@ -27,7 +31,7 @@ protected override async void RunTestCases( executionMessageSink, executionOptions)) { - await assemblyRunner.RunAsync(); + await assemblyRunner.RunAsync().ConfigureAwait(false); } } } diff --git a/nuget.config b/nuget.config new file mode 100644 index 00000000..67eb9d4d --- /dev/null +++ b/nuget.config @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + From 371cad3fc520fa25857800b4b6947fd7e730aaf7 Mon Sep 17 00:00:00 2001 From: Dennis Dyatlov Date: Mon, 25 Nov 2024 15:00:01 +0000 Subject: [PATCH 2/7] add packages:read permission to github_token --- .github/workflows/net-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/net-ci.yml b/.github/workflows/net-ci.yml index 7cac0ebc..f930ee8b 100644 --- a/.github/workflows/net-ci.yml +++ b/.github/workflows/net-ci.yml @@ -19,6 +19,8 @@ jobs: build-test: name: Build & Test runs-on: ubuntu-latest + permissions: + packages: read defaults: run: shell: bash From 8b36a39317f99d48de9e0f799f730944046d6096 Mon Sep 17 00:00:00 2001 From: Dennis Dyatlov Date: Mon, 25 Nov 2024 15:05:42 +0000 Subject: [PATCH 3/7] add nuget source for gh action --- .github/workflows/net-ci.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/net-ci.yml b/.github/workflows/net-ci.yml index f930ee8b..83d3dc0e 100644 --- a/.github/workflows/net-ci.yml +++ b/.github/workflows/net-ci.yml @@ -35,7 +35,13 @@ jobs: dotnet-version: 8.0.x - name: Restore Solution - run: >- + run: | + NUGET_SOURCE_URL="https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" + dotnet nuget add source $NUGET_SOURCE_URL \ + --name ${{ github.repository_owner }}-github \ + --username "${{ github.workflow }}" \ + --password ${{ secrets.GITHUB_TOKEN }} \ + --store-password-in-clear-text dotnet restore - name: Build Solution From d62ddd9f3fe19d9f202b2512eb5cf8cb75fbaf96 Mon Sep 17 00:00:00 2001 From: Dennis Dyatlov Date: Mon, 25 Nov 2024 15:08:47 +0000 Subject: [PATCH 4/7] fix source name --- .github/workflows/net-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/net-ci.yml b/.github/workflows/net-ci.yml index 83d3dc0e..c3121d7a 100644 --- a/.github/workflows/net-ci.yml +++ b/.github/workflows/net-ci.yml @@ -38,7 +38,7 @@ jobs: run: | NUGET_SOURCE_URL="https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" dotnet nuget add source $NUGET_SOURCE_URL \ - --name ${{ github.repository_owner }}-github \ + --name sails-github \ --username "${{ github.workflow }}" \ --password ${{ secrets.GITHUB_TOKEN }} \ --store-password-in-clear-text From 37b6fa59076d492fbe41c8524b9e58a92cede2f6 Mon Sep 17 00:00:00 2001 From: Dennis Dyatlov Date: Mon, 25 Nov 2024 15:15:08 +0000 Subject: [PATCH 5/7] . --- .github/workflows/net-ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/net-ci.yml b/.github/workflows/net-ci.yml index c3121d7a..333b4e7a 100644 --- a/.github/workflows/net-ci.yml +++ b/.github/workflows/net-ci.yml @@ -37,8 +37,9 @@ jobs: - name: Restore Solution run: | NUGET_SOURCE_URL="https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" + dotnet nuget remove source ${{ github.repository_owner }}-github || true dotnet nuget add source $NUGET_SOURCE_URL \ - --name sails-github \ + --name ${{ github.repository_owner }}-github \ --username "${{ github.workflow }}" \ --password ${{ secrets.GITHUB_TOKEN }} \ --store-password-in-clear-text From 3bca6ade6c4a8fd8d63962ca18b9c90da73583c7 Mon Sep 17 00:00:00 2001 From: Dennis Dyatlov Date: Mon, 25 Nov 2024 16:12:57 +0000 Subject: [PATCH 6/7] allow test containers to be executed from different assemblies --- .../Sails.DemoClient.Tests/AssemblyAttributes.cs | 7 ++----- net/tests/Sails.DemoClient.Tests/DemoFactoryTests.cs | 5 +---- net/tests/Sails.DemoClient.Tests/GlobalUsings.cs | 3 +++ .../_Infra/XUnit/Fixtures/SailsFixture.cs | 9 +++++++++ net/tests/Sails.Remoting.Tests/AssemblyAttributes.cs | 2 +- .../Core/RemotingViaNodeClientTests.cs | 2 +- net/tests/Sails.Remoting.Tests/GlobalUsings.cs | 1 - .../_Infra/XUnit/Fixtures/SailsFixture.cs | 9 +++++++++ .../Containers/GearNodeContainer.cs | 9 +++++---- .../Sails.Tests.Shared/XUnit/Fixtures/SailsFixture.cs | 11 +++++++---- 10 files changed, 38 insertions(+), 20 deletions(-) create mode 100644 net/tests/Sails.DemoClient.Tests/GlobalUsings.cs create mode 100644 net/tests/Sails.DemoClient.Tests/_Infra/XUnit/Fixtures/SailsFixture.cs create mode 100644 net/tests/Sails.Remoting.Tests/_Infra/XUnit/Fixtures/SailsFixture.cs diff --git a/net/tests/Sails.DemoClient.Tests/AssemblyAttributes.cs b/net/tests/Sails.DemoClient.Tests/AssemblyAttributes.cs index a365ad10..991f08f6 100644 --- a/net/tests/Sails.DemoClient.Tests/AssemblyAttributes.cs +++ b/net/tests/Sails.DemoClient.Tests/AssemblyAttributes.cs @@ -1,9 +1,6 @@ -using Sails.Tests.Shared.XUnit; -using Xunit; - -[assembly: TestFramework( +[assembly: TestFramework( "Sails.Tests.Shared.XUnit.TestFramework", "Sails.Tests.Shared")] [assembly: AssemblyFixture( - typeof(Sails.Tests.Shared.XUnit.Fixtures.SailsFixture))] + typeof(Sails.DemoClient.Tests._Infra.XUnit.Fixtures.SailsFixture))] diff --git a/net/tests/Sails.DemoClient.Tests/DemoFactoryTests.cs b/net/tests/Sails.DemoClient.Tests/DemoFactoryTests.cs index b0c640fd..60f4f229 100644 --- a/net/tests/Sails.DemoClient.Tests/DemoFactoryTests.cs +++ b/net/tests/Sails.DemoClient.Tests/DemoFactoryTests.cs @@ -1,7 +1,4 @@ -using System.Threading.Tasks; -using Sails.Tests.Shared.XUnit; -using Sails.Tests.Shared.XUnit.Fixtures; -using Xunit; +using Sails.DemoClient.Tests._Infra.XUnit.Fixtures; namespace Sails.DemoClient.Tests; diff --git a/net/tests/Sails.DemoClient.Tests/GlobalUsings.cs b/net/tests/Sails.DemoClient.Tests/GlobalUsings.cs new file mode 100644 index 00000000..8f37676d --- /dev/null +++ b/net/tests/Sails.DemoClient.Tests/GlobalUsings.cs @@ -0,0 +1,3 @@ +global using System.Threading.Tasks; +global using Sails.Tests.Shared.XUnit; +global using Xunit; diff --git a/net/tests/Sails.DemoClient.Tests/_Infra/XUnit/Fixtures/SailsFixture.cs b/net/tests/Sails.DemoClient.Tests/_Infra/XUnit/Fixtures/SailsFixture.cs new file mode 100644 index 00000000..6ec86d5e --- /dev/null +++ b/net/tests/Sails.DemoClient.Tests/_Infra/XUnit/Fixtures/SailsFixture.cs @@ -0,0 +1,9 @@ +namespace Sails.DemoClient.Tests._Infra.XUnit.Fixtures; + +public sealed class SailsFixture : Sails.Tests.Shared.XUnit.Fixtures.SailsFixture +{ + public SailsFixture() + : base("demo-client-tests") + { + } +} diff --git a/net/tests/Sails.Remoting.Tests/AssemblyAttributes.cs b/net/tests/Sails.Remoting.Tests/AssemblyAttributes.cs index 867a9faf..32f26ce1 100644 --- a/net/tests/Sails.Remoting.Tests/AssemblyAttributes.cs +++ b/net/tests/Sails.Remoting.Tests/AssemblyAttributes.cs @@ -3,4 +3,4 @@ "Sails.Tests.Shared")] [assembly: AssemblyFixture( - typeof(Sails.Tests.Shared.XUnit.Fixtures.SailsFixture))] + typeof(Sails.Remoting.Tests._Infra.XUnit.Fixtures.SailsFixture))] diff --git a/net/tests/Sails.Remoting.Tests/Core/RemotingViaNodeClientTests.cs b/net/tests/Sails.Remoting.Tests/Core/RemotingViaNodeClientTests.cs index b390a0ce..1024a7c7 100644 --- a/net/tests/Sails.Remoting.Tests/Core/RemotingViaNodeClientTests.cs +++ b/net/tests/Sails.Remoting.Tests/Core/RemotingViaNodeClientTests.cs @@ -1,4 +1,4 @@ -using Sails.Tests.Shared.XUnit.Fixtures; +using Sails.Remoting.Tests._Infra.XUnit.Fixtures; using Substrate.Gear.Client.GearApi.Model.gprimitives; using Substrate.NetApi.Model.Types.Primitive; diff --git a/net/tests/Sails.Remoting.Tests/GlobalUsings.cs b/net/tests/Sails.Remoting.Tests/GlobalUsings.cs index 65d06e66..8310e6fc 100644 --- a/net/tests/Sails.Remoting.Tests/GlobalUsings.cs +++ b/net/tests/Sails.Remoting.Tests/GlobalUsings.cs @@ -1,5 +1,4 @@ global using System; -global using System.Collections.Generic; global using System.Linq; global using System.Threading; global using System.Threading.Tasks; diff --git a/net/tests/Sails.Remoting.Tests/_Infra/XUnit/Fixtures/SailsFixture.cs b/net/tests/Sails.Remoting.Tests/_Infra/XUnit/Fixtures/SailsFixture.cs new file mode 100644 index 00000000..aba7cea8 --- /dev/null +++ b/net/tests/Sails.Remoting.Tests/_Infra/XUnit/Fixtures/SailsFixture.cs @@ -0,0 +1,9 @@ +namespace Sails.Remoting.Tests._Infra.XUnit.Fixtures; + +public sealed class SailsFixture : Sails.Tests.Shared.XUnit.Fixtures.SailsFixture +{ + public SailsFixture() + : base("remoting-tests") + { + } +} diff --git a/net/tests/Sails.Tests.Shared/Containers/GearNodeContainer.cs b/net/tests/Sails.Tests.Shared/Containers/GearNodeContainer.cs index 277d8773..e42b0b9d 100644 --- a/net/tests/Sails.Tests.Shared/Containers/GearNodeContainer.cs +++ b/net/tests/Sails.Tests.Shared/Containers/GearNodeContainer.cs @@ -16,15 +16,16 @@ public sealed class GearNodeContainer : IAsyncDisposable // TODO: Consider making 'Version' as an optional parameter. // By default the latest version should be taken which can be determined // from the downloaded 'Cargo.toml' file. - public GearNodeContainer(string gearNodeVersion, bool reuse) + public GearNodeContainer(string consumerName, string gearNodeVersion, bool reuse) { + EnsureArg.IsNotNullOrWhiteSpace(consumerName, nameof(consumerName)); EnsureArg.IsNotNullOrWhiteSpace(gearNodeVersion, nameof(gearNodeVersion)); this.nodeInitializationDetector = new NodeInitializationDetector(); this.container = new ContainerBuilder() - .WithName("gear-node-for-tests") + .WithName($"gear-node-for-{consumerName.ToLower()}") .WithImage($"ghcr.io/gear-tech/node:v{gearNodeVersion}") - .WithPortBinding(RpcPort, RpcPort) // Use WithPortBinding(RpcPort, true) if random host port is required + .WithPortBinding(RpcPort, true) .WithEntrypoint("gear") .WithCommand( "--rpc-external", // --rpc-external is required for listening on all interfaces @@ -44,7 +45,7 @@ public GearNodeContainer(string gearNodeVersion, bool reuse) private readonly IContainer container; private readonly bool reuse; - public Uri WsUrl => new($"ws://localhost:{this.container.GetMappedPublicPort(9944)}"); + public Uri WsUrl => new($"ws://localhost:{this.container.GetMappedPublicPort(RpcPort)}"); public ValueTask DisposeAsync() // Do not dispose container if it is reused otherwise it will be stopped diff --git a/net/tests/Sails.Tests.Shared/XUnit/Fixtures/SailsFixture.cs b/net/tests/Sails.Tests.Shared/XUnit/Fixtures/SailsFixture.cs index 157541fe..c027a967 100644 --- a/net/tests/Sails.Tests.Shared/XUnit/Fixtures/SailsFixture.cs +++ b/net/tests/Sails.Tests.Shared/XUnit/Fixtures/SailsFixture.cs @@ -23,15 +23,17 @@ namespace Sails.Tests.Shared.XUnit.Fixtures; public partial class SailsFixture : IAsyncLifetime { - public SailsFixture() - : this(sailsRsVersion: "0.6.3") + public SailsFixture(string consumerName) + : this(consumerName, sailsRsVersion: "0.6.3") { } - public SailsFixture(string sailsRsVersion) + public SailsFixture(string consumerName, string sailsRsVersion) { + EnsureArg.IsNotNullOrWhiteSpace(consumerName, nameof(consumerName)); EnsureArg.IsNotNullOrWhiteSpace(sailsRsVersion, nameof(sailsRsVersion)); + this.consumerName = consumerName; this.sailsRsReleaseTag = $"rs/v{sailsRsVersion}"; this.demoContractIdl = new AsyncLazy( () => this.DownloadStringAssetAsync("demo.idl"), @@ -74,6 +76,7 @@ public SailsFixture(string sailsRsVersion) 10, retry => retry * TimeSpan.FromSeconds(1)); + private readonly string consumerName; private readonly string sailsRsReleaseTag; private readonly AsyncLazy demoContractIdl; private readonly AsyncLazy demoContractWasm; @@ -137,7 +140,7 @@ public async Task InitializeAsync() var gearNodeVersion = matchResult.Groups[1].Value; // The `reuse` parameter can be made configurable if needed - this.gearNodeContainer = new GearNodeContainer(gearNodeVersion, reuse: true); + this.gearNodeContainer = new GearNodeContainer(this.consumerName, gearNodeVersion, reuse: true); await this.gearNodeContainer.StartAsync().ConfigureAwait(false); } From 90cbe22aa32fc79ecac0dc4db17a8af274308047 Mon Sep 17 00:00:00 2001 From: Dennis Dyatlov Date: Mon, 25 Nov 2024 16:17:27 +0000 Subject: [PATCH 7/7] increase node initialization timeout --- net/tests/Sails.Tests.Shared/Containers/GearNodeContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/tests/Sails.Tests.Shared/Containers/GearNodeContainer.cs b/net/tests/Sails.Tests.Shared/Containers/GearNodeContainer.cs index e42b0b9d..12fbc477 100644 --- a/net/tests/Sails.Tests.Shared/Containers/GearNodeContainer.cs +++ b/net/tests/Sails.Tests.Shared/Containers/GearNodeContainer.cs @@ -39,7 +39,7 @@ public GearNodeContainer(string consumerName, string gearNodeVersion, bool reuse } private const ushort RpcPort = 9944; - private static readonly TimeSpan NodeInitializationTimeout = TimeSpan.FromSeconds(10); + private static readonly TimeSpan NodeInitializationTimeout = TimeSpan.FromSeconds(30); private readonly NodeInitializationDetector nodeInitializationDetector; private readonly IContainer container;