Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@
<PackageVersion Include="PropertyChanging.Fody" Version="1.31.0" />
<PackageVersion Include="PublicApiGenerator" Version="11.5.4" />
<PackageVersion Include="RavenDB.Embedded" Version="6.2.17" />
<PackageVersion Include="Testcontainers.MsSql" Version="4.13.0" />
<PackageVersion Include="Testcontainers.PostgreSql" Version="4.13.0" />
<PackageVersion Include="ReactiveUI.WPF" Version="22.3.1" />
<PackageVersion Include="Seq.Extensions.Logging" Version="9.0.0" />
<PackageVersion Include="ServiceControl.Contracts" Version="5.1.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,8 @@
<ItemGroup>
<Artifact Include="$(OutputPath)" DestinationFolder="$(ArtifactsPath)Particular.ServiceControl/Persisters/PostgreSQL" />
</ItemGroup>
<ItemGroup>
<InternalsVisibleTo Include="ServiceControl.Persistence.Tests.PostgreSql" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,9 @@
<ItemGroup>
<Artifact Include="$(OutputPath)" DestinationFolder="$(ArtifactsPath)Particular.ServiceControl/Persisters/SQLServer" />
</ItemGroup>

<ItemGroup>
<InternalsVisibleTo Include="ServiceControl.Persistence.Tests.SqlServer" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
public class PersistenceTestsContext : IPersistenceTestsContext
{
public PersistenceSettings PersistenceSettings { get; private set; }
public string GenerateFailedMessageRecordId(string messageId) => throw new System.NotImplementedException();

public Task Setup(IHostApplicationBuilder hostBuilder)
{
Expand Down
5 changes: 5 additions & 0 deletions src/ServiceControl.Persistence.Tests.PostgreSql/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[*.cs]

# Justification: ServiceControl app has no synchronization context
dotnet_diagnostic.CA2007.severity = none

Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// ReSharper disable once CheckNamespace
namespace ServiceControl.Persistence.Tests;

using System.Threading.Tasks;
using EFCore.PostgreSql;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

public class PersistenceTestsContext : IPersistenceTestsContext
{
public async Task Setup(IHostApplicationBuilder hostBuilder)
{
PersistenceSettings = new PostgreSqlPersisterSettings
{
ConnectionString = await PostgreSqlSharedContainer.GetConnectionStringAsync()
};

var persistence = new PostgreSqlPersistenceConfiguration().Create(PersistenceSettings);

persistence.AddPersistence(hostBuilder.Services);
persistence.AddInstaller(hostBuilder.Services);
}

public async Task PostSetup(IHost host)
{
using var scope = host.Services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<PostgreSqlServiceControlDbContext>();
await db.Database.EnsureCreatedAsync();
}

public Task TearDown() => Task.CompletedTask;

public void CompleteDatabaseOperation() { }

public PersistenceSettings PersistenceSettings { get; set; }

public string GenerateFailedMessageRecordId(string messageId) => messageId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
namespace ServiceControl.Persistence.Tests;

using System;
using System.Threading;
using System.Threading.Tasks;
using Testcontainers.PostgreSql;

static class PostgreSqlSharedContainer
{
public static async Task<string> GetConnectionStringAsync(CancellationToken ct = default)
{
var envConnStr = Environment.GetEnvironmentVariable("ServiceControl_Persistence_PostgreSql_ConnectionString");
if (!string.IsNullOrEmpty(envConnStr))
{
return envConnStr;
}

if (container != null)
{
return container.GetConnectionString();
}

await semaphore.WaitAsync(ct);
try
{
container ??= await StartContainerAsync(ct);
return container.GetConnectionString();
}
finally
{
semaphore.Release();
}
}

public static async Task Stop() => await (container?.DisposeAsync() ?? ValueTask.CompletedTask);

static async Task<PostgreSqlContainer> StartContainerAsync(CancellationToken ct)
{
var c = new PostgreSqlBuilder("postgres:16-alpine")
.Build();
await c.StartAsync(ct);
return c;
}

static PostgreSqlContainer container;
static readonly SemaphoreSlim semaphore = new(1, 1);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\ServiceControl.Infrastructure\ServiceControl.Infrastructure.csproj" />
<ProjectReference Include="..\ServiceControl\ServiceControl.csproj" />
<ProjectReference Include="..\ServiceControl.Persistence.EFCore.PostgreSql\ServiceControl.Persistence.EFCore.PostgreSql.csproj" />
<ProjectReference Include="..\ServiceControl.Transports.Learning\ServiceControl.Transports.Learning.csproj" />
<ProjectReference Include="..\TestHelper\TestHelper.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="GitHubActionsTestLogger" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="NServiceBus.Testing" />
<PackageReference Include="NUnit" />
<PackageReference Include="NUnit.Analyzers" />
<PackageReference Include="NUnit3TestAdapter" />
<PackageReference Include="Particular.Approvals" />
<PackageReference Include="PublicApiGenerator" />
<PackageReference Include="Testcontainers.PostgreSql" />
</ItemGroup>

<ItemGroup>
<Compile Include="..\ServiceControl.Persistence.Tests\**\*.cs" LinkBase="Shared" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace ServiceControl;

using System.Threading.Tasks;
using NUnit.Framework;
using Persistence.Tests;

[SetUpFixture]
public class StopSharedPostgreSql
{
[OneTimeTearDown]
public async Task Teardown() => await PostgreSqlSharedContainer.Stop();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[assembly: IncludeInTestCategory("PostgreSqlPersistence")]
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public async Task PostSetup(IHost host)
public async Task TearDown() => await embeddedServer.DeleteDatabase(databaseName);

public PersistenceSettings PersistenceSettings { get; private set; }
public string GenerateFailedMessageRecordId(string messageId) => FailedMessageIdGenerator.MakeDocumentId(messageId);

public IDocumentStore DocumentStore { get; private set; }

Expand Down
5 changes: 5 additions & 0 deletions src/ServiceControl.Persistence.Tests.SqlServer/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[*.cs]

# Justification: ServiceControl app has no synchronization context
dotnet_diagnostic.CA2007.severity = none

Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// ReSharper disable once CheckNamespace
namespace ServiceControl.Persistence.Tests;

using System.Threading.Tasks;
using EFCore.SqlServer;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

public class PersistenceTestsContext : IPersistenceTestsContext
{
public async Task Setup(IHostApplicationBuilder hostBuilder)
{
PersistenceSettings = new SqlServerPersisterSettings
{
ConnectionString = await SqlServerSharedContainer.GetConnectionStringAsync()
};

var persistence = new SqlServerPersistenceConfiguration().Create(PersistenceSettings);

persistence.AddPersistence(hostBuilder.Services);
persistence.AddInstaller(hostBuilder.Services);
}

public async Task PostSetup(IHost host)
{
using var scope = host.Services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<SqlServerServiceControlDbContext>();
await db.Database.EnsureCreatedAsync();
}

public Task TearDown() => Task.CompletedTask;

public void CompleteDatabaseOperation() { }

public PersistenceSettings PersistenceSettings { get; set; }

public string GenerateFailedMessageRecordId(string messageId) => messageId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\ServiceControl.Infrastructure\ServiceControl.Infrastructure.csproj" />
<ProjectReference Include="..\ServiceControl\ServiceControl.csproj" />
<ProjectReference Include="..\ServiceControl.Persistence.EFCore.SqlServer\ServiceControl.Persistence.EFCore.SqlServer.csproj" />
<ProjectReference Include="..\ServiceControl.Transports.Learning\ServiceControl.Transports.Learning.csproj" />
<ProjectReference Include="..\TestHelper\TestHelper.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="GitHubActionsTestLogger" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="NServiceBus.Testing" />
<PackageReference Include="NUnit" />
<PackageReference Include="NUnit.Analyzers" />
<PackageReference Include="NUnit3TestAdapter" />
<PackageReference Include="Particular.Approvals" />
<PackageReference Include="PublicApiGenerator" />
<PackageReference Include="Testcontainers.MsSql" />
</ItemGroup>

<ItemGroup>
<Compile Include="..\ServiceControl.Persistence.Tests\**\*.cs" LinkBase="Shared" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
namespace ServiceControl.Persistence.Tests;

using System;
using System.Threading;
using System.Threading.Tasks;
using Testcontainers.MsSql;

static class SqlServerSharedContainer
{
public static async Task<string> GetConnectionStringAsync(CancellationToken ct = default)
{
var envConnStr = Environment.GetEnvironmentVariable("ServiceControl_Persistence_SqlServer_ConnectionString");
if (!string.IsNullOrEmpty(envConnStr))
{
return envConnStr;
}

if (container != null)
{
return container.GetConnectionString();
}

await semaphore.WaitAsync(ct);
try
{
container ??= await StartContainerAsync(ct);
return container.GetConnectionString();
}
finally
{
semaphore.Release();
}
}

public static async Task Stop() => await (container?.DisposeAsync() ?? ValueTask.CompletedTask);

static async Task<MsSqlContainer> StartContainerAsync(CancellationToken ct)
{
var c = new MsSqlBuilder("mcr.microsoft.com/mssql/server:2025-latest")
.Build();
await c.StartAsync(ct);
return c;
}

static MsSqlContainer container;
static readonly SemaphoreSlim semaphore = new(1, 1);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace ServiceControl;

using System.Threading.Tasks;
using NUnit.Framework;
using Persistence.Tests;

[SetUpFixture]
public class StopSharedSqlServer
{
[OneTimeTearDown]
public async Task Teardown() => await SqlServerSharedContainer.Stop();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[assembly: IncludeInTestCategory("SqlServerPersistence")]
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ public interface IPersistenceTestsContext
void CompleteDatabaseOperation();

PersistenceSettings PersistenceSettings { get; }

string GenerateFailedMessageRecordId(string messageId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ async Task<FailedMessage> CreateAndStoreFailedMessage(string failedMessageId = n
var failedMessage = new FailedMessage
{
UniqueMessageId = failedMessageId,
Id = FailedMessageIdGenerator.MakeDocumentId(failedMessageId),
Id = PersistenceTestsContext.GenerateFailedMessageRecordId(failedMessageId),
Status = FailedMessageStatus.Unresolved,
ProcessingAttempts =
[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ async Task<FailedMessage> CreateAndStoreFailedMessage(string failedMessageId = n
var failedMessage = new FailedMessage
{
UniqueMessageId = failedMessageId,
Id = FailedMessageIdGenerator.MakeDocumentId(failedMessageId),
Id = PersistenceTestsContext.GenerateFailedMessageRecordId(failedMessageId),
Status = status,
ProcessingAttempts =
[
Expand Down
4 changes: 2 additions & 2 deletions src/ServiceControl.Persistence.Tests/RetryStateTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ public async Task When_a_selection_is_staged_each_message_is_audited_as_a_batch(

var messages = ids.Select(id => new FailedMessage
{
Id = FailedMessageIdGenerator.MakeDocumentId(id),
Id = PersistenceTestsContext.GenerateFailedMessageRecordId(id),
UniqueMessageId = id,
Status = FailedMessageStatus.Unresolved,
ProcessingAttempts =
Expand Down Expand Up @@ -318,7 +318,7 @@ async Task CreateAFailedMessageAndMarkAsPartOfRetryBatch(RetryingManager retryMa
{
var messages = messageIds.Select(id => new FailedMessage
{
Id = FailedMessageIdGenerator.MakeDocumentId(id),
Id = PersistenceTestsContext.GenerateFailedMessageRecordId(id),
UniqueMessageId = id,
FailureGroups =
[
Expand Down
2 changes: 2 additions & 0 deletions src/ServiceControl.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@
<Project Path="ServiceControl.AcceptanceTests.RavenDB/ServiceControl.AcceptanceTests.RavenDB.csproj" />
<Project Path="ServiceControl.Persistence.Tests.InMemory/ServiceControl.Persistence.Tests.InMemory.csproj" />
<Project Path="ServiceControl.Persistence.Tests.RavenDB/ServiceControl.Persistence.Tests.RavenDB.csproj" />
<Project Path="ServiceControl.Persistence.Tests.PostgreSql/ServiceControl.Persistence.Tests.PostgreSql.csproj" />
<Project Path="ServiceControl.Persistence.Tests.SqlServer/ServiceControl.Persistence.Tests.SqlServer.csproj" />
<Project Path="ServiceControl.UnitTests/ServiceControl.UnitTests.csproj" />
</Folder>
<Folder Name="/Instances/Shared/">
Expand Down
2 changes: 2 additions & 0 deletions src/ServiceControl/ServiceControl.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@
<ItemGroup>
<InternalsVisibleTo Include="ServiceControl.AcceptanceTests.RavenDB" />
<InternalsVisibleTo Include="ServiceControl.MultiInstance.AcceptanceTests" />
<InternalsVisibleTo Include="ServiceControl.Persistence.Tests.PostgreSql" />
<InternalsVisibleTo Include="ServiceControl.Persistence.Tests.RavenDB" />
<InternalsVisibleTo Include="ServiceControl.Persistence.Tests.SqlServer" />
<InternalsVisibleTo Include="ServiceControl.UnitTests" />
</ItemGroup>

Expand Down