-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
tests(net): introduce helpers and fixtures for tests (#644)
- Loading branch information
1 parent
0756f12
commit fb07939
Showing
18 changed files
with
828 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ target/ | |
# C# | ||
net/**/[Bb]in/ | ||
net/**/[Oo]bj/ | ||
net/**/*.trx | ||
|
||
# js | ||
node_modules/ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
25 changes: 25 additions & 0 deletions
25
net/tests/Sails.Remoting.Tests/Core/RemotingViaNodeClientTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
using System.Threading.Tasks; | ||
using Sails.Remoting.Tests._Infra.XUnit.Fixtures; | ||
using Sails.Tests.Shared.XUnit; | ||
using Xunit; | ||
|
||
namespace Sails.Remoting.Tests.Core; | ||
|
||
public sealed class RemotingViaNodeClientTests : IAssemblyFixture<SailsFixture> | ||
{ | ||
public RemotingViaNodeClientTests(SailsFixture sailsFixture) | ||
{ | ||
this.sailsFixture = sailsFixture; | ||
} | ||
|
||
private readonly SailsFixture sailsFixture; | ||
|
||
[Fact] | ||
public async Task Test() | ||
{ | ||
var demoIdl = await this.sailsFixture.GetDemoContractIdlAsync(); | ||
var demoContractWasm = await this.sailsFixture.GetDemoContractWasmAsync(); | ||
var noSvcsProgIdl = await this.sailsFixture.GetNoSvcsProgContractIdlAsync(); | ||
var gearNodeWsUrl = this.sailsFixture.GearNodeWsUrl; | ||
} | ||
} |
28 changes: 28 additions & 0 deletions
28
net/tests/Sails.Remoting.Tests/Sails.Remoting.Tests.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<IsPackable>false</IsPackable> | ||
<IsTestProject>true</IsTestProject> | ||
<NoWarn>$(NoWarn);xUnit1041</NoWarn> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="coverlet.collector"> | ||
<PrivateAssets>all</PrivateAssets> | ||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | ||
</PackageReference> | ||
<PackageReference Include="Microsoft.NET.Test.Sdk" /> | ||
<PackageReference Include="Nito.AsyncEx" /> | ||
<PackageReference Include="xunit" /> | ||
<PackageReference Include="xunit.runner.visualstudio"> | ||
<PrivateAssets>all</PrivateAssets> | ||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | ||
</PackageReference> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\Sails.Tests.Shared\Sails.Tests.Shared.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
148 changes: 148 additions & 0 deletions
148
net/tests/Sails.Remoting.Tests/_Infra/XUnit/Fixtures/SailsFixture.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
using EnsureThat; | ||
using Nito.AsyncEx; | ||
using System.IO; | ||
using System.Text.RegularExpressions; | ||
using System.Threading.Tasks; | ||
using System.Threading; | ||
using System; | ||
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))] | ||
|
||
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<string>( | ||
() => this.DownloadStringAsset("demo.idl"), | ||
AsyncLazyFlags.RetryOnFailure); | ||
this.demoContractWasm = new AsyncLazy<MemoryStream>( | ||
() => this.DownloadOctetAsset("demo.wasm"), | ||
AsyncLazyFlags.RetryOnFailure); | ||
this.noSvcsProgContractIdl = new AsyncLazy<string>( | ||
() => this.DownloadStringAsset("no-svcs-prog.idl"), | ||
AsyncLazyFlags.RetryOnFailure); | ||
this.noSvcsProgContractWasm = new AsyncLazy<MemoryStream>( | ||
() => 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<string> demoContractIdl; | ||
private readonly AsyncLazy<MemoryStream> demoContractWasm; | ||
private readonly AsyncLazy<string> noSvcsProgContractIdl; | ||
private readonly AsyncLazy<MemoryStream> 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<string> GetDemoContractIdlAsync() | ||
=> this.demoContractIdl.Task; | ||
|
||
public async Task<ReadOnlyMemory<byte>> GetDemoContractWasmAsync() | ||
{ | ||
var byteStream = await this.demoContractWasm; | ||
Ensure.Comparable.IsLte(byteStream.Length, int.MaxValue); | ||
return new ReadOnlyMemory<byte>(byteStream.GetBuffer(), start: 0, length: (int)byteStream.Length); | ||
} | ||
|
||
public Task<string> GetNoSvcsProgContractIdlAsync() | ||
=> this.noSvcsProgContractIdl.Task; | ||
|
||
public async Task<ReadOnlyMemory<byte>> GetNoSvcsProgContractWasmAsync() | ||
{ | ||
var byteStream = await this.noSvcsProgContractWasm; | ||
Ensure.Comparable.IsLte(byteStream.Length, int.MaxValue); | ||
return new ReadOnlyMemory<byte>(byteStream.GetBuffer(), start: 0, length: (int)byteStream.Length); | ||
} | ||
|
||
private async Task<string> 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<MemoryStream> 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<string> 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(); | ||
} |
15 changes: 15 additions & 0 deletions
15
net/tests/Sails.Remoting.Tests/_Infra/XUnit/TestFramework.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
using Xunit.Abstractions; | ||
|
||
[assembly: Xunit.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) | ||
{ | ||
} | ||
} |
53 changes: 53 additions & 0 deletions
53
net/tests/Sails.Tests.Shared/Containers/GearNodeContainer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
using System; | ||
using System.Threading.Tasks; | ||
using DotNet.Testcontainers.Builders; | ||
using DotNet.Testcontainers.Containers; | ||
using EnsureThat; | ||
|
||
namespace Sails.Tests.Shared.Containers; | ||
|
||
// TODO: Consider introducing ContainerBuilder similar to how it is done | ||
// for modules shipped along with Testcontainers library. | ||
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) | ||
{ | ||
EnsureArg.IsNotNullOrWhiteSpace(gearNodeVersion, nameof(gearNodeVersion)); | ||
|
||
this.container = new ContainerBuilder() | ||
.WithName("gear-node-for-tests") | ||
.WithImage($"ghcr.io/gear-tech/node:v{gearNodeVersion}") | ||
.WithPortBinding(RpcPort, RpcPort) // Use WithPortBinding(RpcPort, true) if random host port is required | ||
.WithEntrypoint("gear") | ||
.WithCommand( | ||
"--rpc-external", // --rpc-external is required for listening on all interfaces | ||
"--dev", | ||
"--tmp") | ||
.WithEnvironment("RUST_LOG", "gear=debug,pallet_gear=debug,gwasm=debug") | ||
.WithReuse(reuse) | ||
.Build(); | ||
this.reuse = reuse; | ||
} | ||
|
||
private const ushort RpcPort = 9944; | ||
|
||
private readonly IContainer container; | ||
private readonly bool reuse; | ||
|
||
public Uri WsUrl => new($"ws://localhost:{this.container.GetMappedPublicPort(9944)}"); | ||
|
||
public ValueTask DisposeAsync() | ||
// Do not dispose container if it is reused otherwise it will be stopped | ||
// which we don't want for this particular container. For another one we might | ||
// choose the opposite behavior though. | ||
// https://dotnet.testcontainers.org/api/resource_reuse/ | ||
=> this.reuse | ||
? ValueTask.CompletedTask | ||
: this.container.DisposeAsync(); | ||
|
||
public Task StartAsync() | ||
=> this.container.StartAsync(); | ||
} |
Oops, something went wrong.