Skip to content

Commit

Permalink
Implement SQL query transaction isolation level from Akka.NET 1.5.3 (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
Arkatufus authored Apr 21, 2023
1 parent 2c73867 commit 4b2bceb
Show file tree
Hide file tree
Showing 16 changed files with 660 additions and 88 deletions.
2 changes: 2 additions & 0 deletions build.fsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ Target "RunTests" <| fun _ ->
let projects =
match (isWindows) with
| true -> !! "./src/**/*.Tests.*sproj"
-- "./src/**/*.Performance.Tests.*sproj"
| _ -> !! "./src/**/*.Tests.*sproj" // if you need to filter specs for Linux vs. Windows, do it here

ensureDirectory outputTests
Expand All @@ -158,6 +159,7 @@ Target "RunTestsNet" <| fun _ ->
let projects =
match (isWindows) with
| true -> !! "./src/**/*.Tests.*sproj"
-- "./src/**/*.Performance.Tests.*sproj"
| _ -> !! "./src/**/*.Tests.*sproj" // if you need to filter specs for Linux vs. Windows, do it here

ensureDirectory outputTests
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(NetFrameworkTestVersion);$(NetCoreTestVersion)</TargetFrameworks>
<IsPackable>false</IsPackable>
</PropertyGroup>

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

<ItemGroup>
<ProjectReference Include="..\Akka.Persistence.PostgreSql\Akka.Persistence.PostgreSql.csproj" />
</ItemGroup>
</Project>
85 changes: 85 additions & 0 deletions src/Akka.Persistence.PostgreSql.Performance.Tests/DbUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//-----------------------------------------------------------------------
// <copyright file="DbUtils.cs" company="Akka.NET Project">
// Copyright (C) 2009-2016 Lightbend Inc. <http://www.lightbend.com>
// Copyright (C) 2013-2016 Akka.NET project <https://github.com/akkadotnet/akka.net>
// </copyright>
//-----------------------------------------------------------------------

using System;
using Npgsql;

namespace Akka.Persistence.PostgreSql.Performance.Tests
{
public static class DbUtils
{
public static string ConnectionString { get; private set; }

public static void Initialize(PostgresFixture fixture)
{
ConnectionString = fixture.ConnectionString;
var connectionBuilder = new NpgsqlConnectionStringBuilder(ConnectionString);

//connect to postgres database to create a new database
var databaseName = connectionBuilder.Database;
connectionBuilder.Database = databaseName;
ConnectionString = connectionBuilder.ToString();

using (var conn = new NpgsqlConnection(ConnectionString))
{
conn.Open();

bool dbExists;
using (var cmd = new NpgsqlCommand())
{
cmd.CommandText = $@"SELECT TRUE FROM pg_database WHERE datname='{databaseName}'";
cmd.Connection = conn;

var result = cmd.ExecuteScalar();
dbExists = result != null && Convert.ToBoolean(result);
}

if (dbExists)
{
Clean();
}
else
{
DoCreate(conn, databaseName);
}
}
}

public static void Clean()
{
using (var conn = new NpgsqlConnection(ConnectionString))
{
conn.Open();

DoClean(conn);
}
}

private static void DoCreate(NpgsqlConnection conn, string databaseName)
{
using (var cmd = new NpgsqlCommand())
{
cmd.CommandText = $@"CREATE DATABASE {databaseName}";
cmd.Connection = conn;
cmd.ExecuteNonQuery();
}
}

private static void DoClean(NpgsqlConnection conn)
{
using (var cmd = new NpgsqlCommand())
{
cmd.CommandText = @"
DROP TABLE IF EXISTS public.event_journal;
DROP TABLE IF EXISTS public.snapshot_store;
DROP TABLE IF EXISTS public.metadata;";
cmd.Connection = conn;
cmd.ExecuteNonQuery();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
using Xunit;
using Xunit.Abstractions;

namespace Akka.Persistence.PostgreSql.Tests.Performance
namespace Akka.Persistence.PostgreSql.Performance.Tests
{
[Collection("PostgreSqlSpec")]
public class PostgreSqlJournalPerfSpec : JournalPerfSpec
Expand Down
127 changes: 127 additions & 0 deletions src/Akka.Persistence.PostgreSql.Performance.Tests/PostgresFixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Akka.Util;
using Docker.DotNet;
using Docker.DotNet.Models;
using Xunit;

namespace Akka.Persistence.PostgreSql.Performance.Tests
{
[CollectionDefinition("PostgreSqlSpec")]
public sealed class PostgresSpecsFixture : ICollectionFixture<PostgresFixture>
{
}

/// <summary>
/// Fixture used to run PostgresSQL Server
/// </summary>
public class PostgresFixture : IAsyncLifetime
{
protected readonly string PostgresContainerName = $"postgresSqlServer-{Guid.NewGuid():N}";
protected DockerClient Client;

public PostgresFixture()
{
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 => "postgres";
protected string Tag => "latest";

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

public string ConnectionString { get; private set; }

public async Task InitializeAsync()
{
var images = await Client.Images.ListImagesAsync(new ImagesListParameters
{
Filters = new Dictionary<string, IDictionary<string, bool>>
{
{
"reference",
new Dictionary<string, bool>
{
{PostgresImageName, 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 = PostgresImageName,
Name = PostgresContainerName,
Tty = true,
ExposedPorts = new Dictionary<string, EmptyStruct>
{
{"5432/tcp", new EmptyStruct()}
},
HostConfig = new HostConfig
{
PortBindings = new Dictionary<string, IList<PortBinding>>
{
{
"5432/tcp",
new List<PortBinding>
{
new PortBinding
{
HostPort = $"{sqlServerHostPort}"
}
}
}
}
},
Env = new[]
{
"POSTGRES_PASSWORD=postgres",
"POSTGRES_USER=postgres"
}
});

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

// Provide a 10 second startup delay
await Task.Delay(TimeSpan.FromSeconds(10));

ConnectionString = $"Server=127.0.0.1;Port={sqlServerHostPort};" +
"Database=postgres;User Id=postgres;Password=postgres";
}

public async Task DisposeAsync()
{
if (Client != null)
{
await Client.Containers.StopContainerAsync(PostgresContainerName, new ContainerStopParameters());
await Client.Containers.RemoveContainerAsync(PostgresContainerName,
new ContainerRemoveParameters { Force = true });
Client.Dispose();
}
}
}
}
6 changes: 6 additions & 0 deletions src/Akka.Persistence.PostgreSql.Tests/DbUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

using Npgsql;
using System;
using System.IO;

namespace Akka.Persistence.PostgreSql.Tests
{
Expand Down Expand Up @@ -47,6 +48,11 @@ public static void Initialize(PostgresFixture fixture)
DoCreate(conn, databaseName);
}
}

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

public static void Clean()
Expand Down
Loading

0 comments on commit 4b2bceb

Please sign in to comment.