Skip to content

Commit

Permalink
Split performance unit tests into its own project (akkadotnet#306)
Browse files Browse the repository at this point in the history
  • Loading branch information
Arkatufus authored Apr 25, 2023
1 parent 5cbf1fe commit 8fbf90a
Show file tree
Hide file tree
Showing 8 changed files with 314 additions and 9 deletions.
6 changes: 6 additions & 0 deletions Akka.Persistence.SqlServer.sln
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.Persistence.SqlServer"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.Persistence.SqlServer.Tests", "src\Akka.Persistence.SqlServer.Tests\Akka.Persistence.SqlServer.Tests.csproj", "{DEAC600E-5B71-4124-BE4B-5BF26C21575E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.Persistence.SqlServer.Performance.Tests", "src\Akka.Persistence.SqlServer.Performance.Tests\Akka.Persistence.SqlServer.Performance.Tests.csproj", "{5B792D05-2CCE-4513-BAAD-100394E9E161}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -38,6 +40,10 @@ Global
{DEAC600E-5B71-4124-BE4B-5BF26C21575E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DEAC600E-5B71-4124-BE4B-5BF26C21575E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DEAC600E-5B71-4124-BE4B-5BF26C21575E}.Release|Any CPU.Build.0 = Release|Any CPU
{5B792D05-2CCE-4513-BAAD-100394E9E161}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5B792D05-2CCE-4513-BAAD-100394E9E161}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5B792D05-2CCE-4513-BAAD-100394E9E161}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5B792D05-2CCE-4513-BAAD-100394E9E161}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
2 changes: 2 additions & 0 deletions build.fsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,9 @@ Target "RunTests" (fun _ ->
let projects =
match (isWindows) with
| true -> !! "./src/**/*.Tests.csproj"
-- "./src/**/*.Performance.Tests.csproj"
| _ -> !! "./src/**/*.Tests.csproj" // if you need to filter specs for Linux vs. Windows, do it here
-- "./src/**/*.Performance.Tests.csproj"

let runSingleProject project =
let arguments =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup Condition="'$(OS)' == 'Windows_NT'">
<TargetFrameworks>$(NetFrameworkTestVersion);$(NetCoreTestVersion)</TargetFrameworks>
<IsPackable>false</IsPackable>
</PropertyGroup>

<!-- disable .NET Framework (Mono) on Linux-->
<PropertyGroup Condition="'$(OS)' != 'Windows_NT'">
<TargetFramework>$(NetCoreTestVersion)</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Data.SqlClient" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="Akka.Persistence.Sql.TestKit" />
<PackageReference Include="Docker.DotNet" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.runner.visualstudio" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Akka.Persistence.SqlServer\Akka.Persistence.SqlServer.csproj" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
using Xunit;
using Xunit.Abstractions;

namespace Akka.Persistence.SqlServer.Tests
namespace Akka.Persistence.SqlServer.Performance.Tests
{
[Collection("SqlServerSpec")]
public class BatchingSqlServerJournalPerfSpec : JournalPerfSpec, IDisposable
Expand Down
84 changes: 84 additions & 0 deletions src/Akka.Persistence.SqlServer.Performance.Tests/DbUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// -----------------------------------------------------------------------
// <copyright file="DbUtils.cs" company="Akka.NET Project">
// Copyright (C) 2013 - 2023 .NET Foundation <https://github.com/akkadotnet/akka.net>
// </copyright>
// -----------------------------------------------------------------------

using System;
using System.IO;
using Microsoft.Data.SqlClient;

namespace Akka.Persistence.SqlServer.Performance.Tests
{
public static class DbUtils
{
private static SqlConnectionStringBuilder _builder;
public static string ConnectionString => _builder.ToString();

public static void Initialize(string connectionString)
{
_builder = new SqlConnectionStringBuilder(connectionString);
var databaseName = $"akka_persistence_tests_{Guid.NewGuid()}";
_builder.InitialCatalog = databaseName;

var connectionBuilder = new SqlConnectionStringBuilder(connectionString)
{
InitialCatalog = "master"
};

using (var conn = new SqlConnection(connectionBuilder.ToString()))
{
conn.Open();

using (var cmd = new SqlCommand())
{
cmd.CommandText = $@"
IF db_id('{databaseName}') IS NULL
BEGIN
CREATE DATABASE [{databaseName}];
END";
cmd.Connection = conn;
cmd.ExecuteScalar();
}
}

// Delete local snapshot flat file database
var path = "./snapshots";
if (Directory.Exists(path))
Directory.Delete(path, true);
}

public static void Clean()
{
var databaseName = $"akka_persistence_tests_{Guid.NewGuid()}";
_builder.InitialCatalog = databaseName;

var connectionBuilder = new SqlConnectionStringBuilder(ConnectionString)
{
InitialCatalog = "master"
};

using (var conn = new SqlConnection(connectionBuilder.ToString()))
{
conn.Open();

using (var cmd = new SqlCommand())
{
cmd.CommandText = $@"
IF db_id('{databaseName}') IS NULL
BEGIN
CREATE DATABASE [{databaseName}];
END
";
cmd.Connection = conn;
cmd.ExecuteScalar();
}
}

// Delete local snapshot flat file database
var path = "./snapshots";
if (Directory.Exists(path))
Directory.Delete(path, true);
}
}
}
186 changes: 186 additions & 0 deletions src/Akka.Persistence.SqlServer.Performance.Tests/SqlServerFixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
// -----------------------------------------------------------------------
// <copyright file="SqlServerFixture.cs" company="Akka.NET Project">
// Copyright (C) 2013 - 2023 .NET Foundation <https://github.com/akkadotnet/akka.net>
// </copyright>
// -----------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Akka.Util;
using Docker.DotNet;
using Docker.DotNet.Models;
using Xunit;
using Xunit.Sdk;

namespace Akka.Persistence.SqlServer.Performance.Tests
{
[CollectionDefinition("SqlServerSpec")]
public sealed class SqlServerSpecsFixture : ICollectionFixture<SqlServerFixture>
{
}

/// <summary>
/// Fixture used to run SQL Server
/// </summary>
public class SqlServerFixture : IAsyncLifetime
{
protected readonly string SqlContainerName = $"sqlserver-{Guid.NewGuid():N}";
protected DockerClient Client;

public SqlServerFixture()
{
DockerClientConfiguration config;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
config = new DockerClientConfiguration(new Uri("unix://var/run/docker.sock"));
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
config = new DockerClientConfiguration(new Uri("npipe://./pipe/docker_engine"));
else
throw new NotSupportedException($"Unsupported OS [{RuntimeInformation.OSDescription}]");

Client = config.CreateClient();
}

protected string ImageName => "mcr.microsoft.com/mssql/server";
protected string Tag => "2019-latest";

protected string SqlServerImageName => $"{ImageName}:{Tag}";

public string ConnectionString { get; private set; }

public async Task InitializeAsync()
{
var sysInfo = await Client.System.GetSystemInfoAsync();
if (sysInfo.OSType.ToLowerInvariant() != "linux")
throw new TestClassException("MSSQL docker image only available for linux containers");

var images = await Client.Images.ListImagesAsync(new ImagesListParameters
{
Filters = new Dictionary<string, IDictionary<string, bool>>
{
{
"reference",
new Dictionary<string, bool>
{
{ SqlServerImageName, true }
}
}
}
});

if (images.Count == 0)
await Client.Images.CreateImageAsync(
new ImagesCreateParameters { FromImage = ImageName, Tag = Tag }, null,
new Progress<JSONMessage>(message =>
{
Console.WriteLine(!string.IsNullOrEmpty(message.ErrorMessage)
? message.ErrorMessage
: $"{message.ID} {message.Status} {message.ProgressMessage}");
}));

var sqlServerHostPort = ThreadLocalRandom.Current.Next(9000, 10000);

// create the container
await Client.Containers.CreateContainerAsync(new CreateContainerParameters
{
Image = SqlServerImageName,
Name = SqlContainerName,
Tty = true,
ExposedPorts = new Dictionary<string, EmptyStruct>
{
{ "1433/tcp", new EmptyStruct() }
},
HostConfig = new HostConfig
{
PortBindings = new Dictionary<string, IList<PortBinding>>
{
{
"1433/tcp",
new List<PortBinding>
{
new PortBinding
{
HostPort = $"{sqlServerHostPort}"
}
}
}
}
},
Env = new[]
{
"ACCEPT_EULA=Y",
"MSSQL_SA_PASSWORD=l0l!Th1sIsOpenSource"
}
});

// start the container
await Client.Containers.StartContainerAsync(SqlContainerName, new ContainerStartParameters());

// Wait until MSSQL is completely ready
var logStream = await Client.Containers.GetContainerLogsAsync(SqlContainerName, new ContainerLogsParameters
{
Follow = true,
ShowStdout = true,
ShowStderr = true
});

string line = null;
var timeoutInMilis = 60000;
using (var reader = new StreamReader(logStream))
{
var stopwatch = Stopwatch.StartNew();
while (stopwatch.ElapsedMilliseconds < timeoutInMilis && (line = await reader.ReadLineAsync()) != null)
{
if (!string.IsNullOrWhiteSpace(line))
Console.WriteLine(line);
if (line.Contains("SQL Server is now ready for client connections.")) break;
}

stopwatch.Stop();
}
#if NETCOREAPP3_1_OR_GREATER
await logStream.DisposeAsync();
#else
logStream.Dispose();
#endif
if (!line?.Contains("SQL Server is now ready for client connections.") ?? false)
throw new Exception("MSSQL docker image failed to run.");

var connectionString = new DbConnectionStringBuilder
{
["Server"] = $"localhost,{sqlServerHostPort}",
["Database"] = "akka_persistence_tests",
["User Id"] = "sa",
["Password"] = "l0l!Th1sIsOpenSource"
};

ConnectionString = connectionString.ToString();
Console.WriteLine($"Connection string: [{ConnectionString}]");

await Task.Delay(10000);
}

public async Task DisposeAsync()
{
if (Client != null)
try
{
await Client.Containers.StopContainerAsync(SqlContainerName, new ContainerStopParameters());
await Client.Containers.RemoveContainerAsync(SqlContainerName,
new ContainerRemoveParameters { Force = true });
}
catch (DockerContainerNotFoundException)
{
// no-op
}
finally
{
Client.Dispose();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
using Xunit;
using Xunit.Abstractions;

namespace Akka.Persistence.SqlServer.Tests
namespace Akka.Persistence.SqlServer.Performance.Tests
{
[Collection("SqlServerSpec")]
public class SqlServerJournalPerfSpec : JournalPerfSpec, IDisposable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup Condition="'$(OS)' == 'Windows_NT'">
<TargetFrameworks>$(NetFrameworkTestVersion);$(NetCoreTestVersion)</TargetFrameworks>
<IsPackable>false</IsPackable>
</PropertyGroup>

<!-- disable .NET Framework (Mono) on Linux-->
<PropertyGroup Condition="'$(OS)' != 'Windows_NT'">
<TargetFrameworks>$(NetCoreTestVersion)</TargetFrameworks>
<TargetFramework>$(NetCoreTestVersion)</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Data.SqlClient" />
<PackageReference Include="Microsoft.NET.Test.Sdk"/>
<PackageReference Include="Akka.Persistence.Sql.TestKit"/>
<PackageReference Include="Docker.DotNet"/>
<PackageReference Include="xunit"/>
<PackageReference Include="xunit.runner.visualstudio"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="Akka.Persistence.Sql.TestKit" />
<PackageReference Include="Docker.DotNet" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.runner.visualstudio" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Akka.Persistence.SqlServer\Akka.Persistence.SqlServer.csproj"/>
<ProjectReference Include="..\Akka.Persistence.SqlServer\Akka.Persistence.SqlServer.csproj" />
</ItemGroup>
</Project>

0 comments on commit 8fbf90a

Please sign in to comment.