diff --git a/src/Akka.Persistence.Sql.Tests/MySql/MySqlSnapshotStoreSaveSnapshotSpec.cs b/src/Akka.Persistence.Sql.Tests/MySql/MySqlSnapshotStoreSaveSnapshotSpec.cs new file mode 100644 index 00000000..34ea7e8b --- /dev/null +++ b/src/Akka.Persistence.Sql.Tests/MySql/MySqlSnapshotStoreSaveSnapshotSpec.cs @@ -0,0 +1,60 @@ +// ----------------------------------------------------------------------- +// +// Copyright (C) 2013-2023 .NET Foundation +// +// ----------------------------------------------------------------------- + +using System; +using Akka.Configuration; +using Akka.Persistence.Sql.Tests.Common.Containers; +using Akka.Persistence.Sql.Tests.Common.Internal.Xunit; +using FluentAssertions.Extensions; +using Xunit; +using Xunit.Abstractions; + +namespace Akka.Persistence.Sql.Tests.MySql +{ +#if !DEBUG + [SkipWindows] +#endif + [Collection(nameof(MySqlPersistenceSpec))] + public class MySqlSnapshotStoreSaveSnapshotSpec: SnapshotStoreSaveSnapshotSpecBase + { + public MySqlSnapshotStoreSaveSnapshotSpec(ITestOutputHelper output, MySqlContainer fixture) + : base(Configuration(fixture), nameof(MySqlSnapshotStoreSaveSnapshotSpec), output) + { + } + + private static Configuration.Config Configuration(MySqlContainer fixture) + { + if (!fixture.InitializeDbAsync().Wait(10.Seconds())) + throw new Exception("Failed to clean up database in 10 seconds"); + + return ConfigurationFactory.ParseString( + $$""" + akka.persistence { + publish-plugin-commands = on + journal { + plugin = "akka.persistence.journal.sql" + sql { + connection-string = "{{fixture.ConnectionString}}" + provider-name = "{{fixture.ProviderName}}" + read-isolation-level = read-committed + write-isolation-level = read-committed + } + } + snapshot-store { + plugin = "akka.persistence.snapshot-store.sql" + sql { + connection-string = "{{fixture.ConnectionString}}" + provider-name = "{{fixture.ProviderName}}" + read-isolation-level = read-committed + write-isolation-level = read-committed + } + } + } + """) + .WithFallback(SqlPersistence.DefaultConfiguration); + } + } +} diff --git a/src/Akka.Persistence.Sql.Tests/PostgreSql/PostgreSqlSnapshotStoreSaveSnapshotSpec.cs b/src/Akka.Persistence.Sql.Tests/PostgreSql/PostgreSqlSnapshotStoreSaveSnapshotSpec.cs new file mode 100644 index 00000000..93296941 --- /dev/null +++ b/src/Akka.Persistence.Sql.Tests/PostgreSql/PostgreSqlSnapshotStoreSaveSnapshotSpec.cs @@ -0,0 +1,49 @@ +// ----------------------------------------------------------------------- +// +// Copyright (C) 2013-2023 .NET Foundation +// +// ----------------------------------------------------------------------- + +using System; +using Akka.Configuration; +using Akka.Persistence.Sql.Tests.Common.Containers; +using Akka.Persistence.Sql.Tests.Common.Internal.Xunit; +using FluentAssertions.Extensions; +using Xunit; +using Xunit.Abstractions; + +namespace Akka.Persistence.Sql.Tests.PostgreSql +{ +#if !DEBUG + [SkipWindows] +#endif + [Collection(nameof(PostgreSqlPersistenceSpec))] + public class PostgreSqlSnapshotStoreSaveSnapshotSpec: SnapshotStoreSaveSnapshotSpecBase + { + public PostgreSqlSnapshotStoreSaveSnapshotSpec(ITestOutputHelper output, PostgreSqlContainer fixture) + : base(Configuration(fixture), nameof(PostgreSqlSnapshotStoreSaveSnapshotSpec), output) + { + } + + private static Configuration.Config Configuration(PostgreSqlContainer fixture) + { + if (!fixture.InitializeDbAsync().Wait(10.Seconds())) + throw new Exception("Failed to clean up database in 10 seconds"); + + return ConfigurationFactory.ParseString( + $$""" + akka.persistence { + publish-plugin-commands = on + snapshot-store { + plugin = "akka.persistence.snapshot-store.sql" + sql { + connection-string = "{{fixture.ConnectionString}}" + provider-name = "{{fixture.ProviderName}}" + } + } + } + """) + .WithFallback(SqlPersistence.DefaultConfiguration); + } + } +} diff --git a/src/Akka.Persistence.Sql.Tests/SnapshotStoreSaveSnapshotSpecBase.cs b/src/Akka.Persistence.Sql.Tests/SnapshotStoreSaveSnapshotSpecBase.cs new file mode 100644 index 00000000..7b91bd66 --- /dev/null +++ b/src/Akka.Persistence.Sql.Tests/SnapshotStoreSaveSnapshotSpecBase.cs @@ -0,0 +1,50 @@ +// ----------------------------------------------------------------------- +// +// Copyright (C) 2013-2023 .NET Foundation +// +// ----------------------------------------------------------------------- + +using System; +using System.Threading.Tasks; +using Akka.Persistence.TCK.Serialization; +using Akka.Persistence.TCK.Snapshot; +using FluentAssertions; +using FluentAssertions.Extensions; +using Xunit; +using Xunit.Abstractions; + +namespace Akka.Persistence.Sql.Tests +{ + public abstract class SnapshotStoreSaveSnapshotSpecBase: SnapshotStoreSaveSnapshotSpec + { + protected SnapshotStoreSaveSnapshotSpecBase(Configuration.Config config, string actorSystemName, ITestOutputHelper? output = null) + : base(config, actorSystemName, output) + { + + } + + [Fact(DisplayName = "Multiple SaveSnapshot invocation with default metadata should not throw")] + public async Task MultipleSnapshotsWithDefaultMetadata() + { + var persistence = Persistence.Instance.Apply(Sys); + var snapshotStore = persistence.SnapshotStoreFor(null); + var snap = new TestPayload(SenderProbe.Ref); + + var now = DateTime.UtcNow; + var metadata = new SnapshotMetadata(PersistenceId, 0, DateTime.MinValue); + snapshotStore.Tell(new SaveSnapshot(metadata, snap), SenderProbe); + var success = await SenderProbe.ExpectMsgAsync(10.Minutes()); + success.Metadata.PersistenceId.Should().Be(metadata.PersistenceId); + success.Metadata.Timestamp.Should().BeAfter(now); + success.Metadata.SequenceNr.Should().Be(metadata.SequenceNr); + + now = DateTime.UtcNow; + metadata = new SnapshotMetadata(PersistenceId, 0, DateTime.MinValue); + snapshotStore.Tell(new SaveSnapshot(metadata, 3), SenderProbe); + success = await SenderProbe.ExpectMsgAsync(); + success.Metadata.PersistenceId.Should().Be(metadata.PersistenceId); + success.Metadata.Timestamp.Should().BeAfter(now); + success.Metadata.SequenceNr.Should().Be(metadata.SequenceNr); + } + } +} diff --git a/src/Akka.Persistence.Sql.Tests/SqlServer/SqlServerSnapshotStoreSaveSnapshotSpec.cs b/src/Akka.Persistence.Sql.Tests/SqlServer/SqlServerSnapshotStoreSaveSnapshotSpec.cs new file mode 100644 index 00000000..7c367f49 --- /dev/null +++ b/src/Akka.Persistence.Sql.Tests/SqlServer/SqlServerSnapshotStoreSaveSnapshotSpec.cs @@ -0,0 +1,29 @@ +// ----------------------------------------------------------------------- +// +// Copyright (C) 2013-2023 .NET Foundation +// +// ----------------------------------------------------------------------- + +using Akka.Persistence.Sql.Tests.Common.Containers; +using Akka.Persistence.Sql.Tests.Common.Internal.Xunit; +using Xunit; +using Xunit.Abstractions; + +namespace Akka.Persistence.Sql.Tests.SqlServer +{ +#if !DEBUG + [SkipWindows] +#endif + [Collection(nameof(SqlServerPersistenceSpec))] + public class SqlServerSnapshotStoreSaveSnapshotSpec: SnapshotStoreSaveSnapshotSpecBase + { + public SqlServerSnapshotStoreSaveSnapshotSpec(ITestOutputHelper output, SqlServerContainer fixture) + : base(Configuration(fixture), nameof(SqlServerSnapshotStoreSaveSnapshotSpec), output) + { + } + + private static Configuration.Config Configuration(SqlServerContainer fixture) + => SqlServerSnapshotSpecConfig.Create(fixture, "snapshotSpec"); + + } +} diff --git a/src/Akka.Persistence.Sql.Tests/Sqlite/MsSqliteSnapshotStoreSaveSnapshotSpec.cs b/src/Akka.Persistence.Sql.Tests/Sqlite/MsSqliteSnapshotStoreSaveSnapshotSpec.cs new file mode 100644 index 00000000..83e5141e --- /dev/null +++ b/src/Akka.Persistence.Sql.Tests/Sqlite/MsSqliteSnapshotStoreSaveSnapshotSpec.cs @@ -0,0 +1,25 @@ +// ----------------------------------------------------------------------- +// +// Copyright (C) 2013-2023 .NET Foundation +// +// ----------------------------------------------------------------------- + +using Akka.Persistence.Sql.Tests.Common.Containers; +using Akka.Persistence.Sql.Tests.Common.Internal.Xunit; +using Xunit; +using Xunit.Abstractions; + +namespace Akka.Persistence.Sql.Tests.Sqlite +{ +#if !DEBUG + [SkipWindows] +#endif + [Collection(nameof(MsSqlitePersistenceSpec))] + public class MsSqliteSnapshotStoreSaveSnapshotSpec: SnapshotStoreSaveSnapshotSpecBase + { + public MsSqliteSnapshotStoreSaveSnapshotSpec(ITestOutputHelper output, MsSqliteContainer fixture) + : base(SqliteSnapshotSpecConfig.Create(fixture), nameof(MsSqliteSnapshotStoreSaveSnapshotSpec), output) + { + } + } +} diff --git a/src/Akka.Persistence.Sql.Tests/Sqlite/SqliteSnapshotStoreSaveSnapshotSpec.cs b/src/Akka.Persistence.Sql.Tests/Sqlite/SqliteSnapshotStoreSaveSnapshotSpec.cs new file mode 100644 index 00000000..e7edc331 --- /dev/null +++ b/src/Akka.Persistence.Sql.Tests/Sqlite/SqliteSnapshotStoreSaveSnapshotSpec.cs @@ -0,0 +1,29 @@ +// ----------------------------------------------------------------------- +// +// Copyright (C) 2013-2023 .NET Foundation +// +// ----------------------------------------------------------------------- + +using Akka.Persistence.Sql.Tests.Common.Containers; +using Akka.Persistence.Sql.Tests.Common.Internal.Xunit; +using Xunit; +using Xunit.Abstractions; + +namespace Akka.Persistence.Sql.Tests.Sqlite +{ +#if !DEBUG + [SkipWindows] +#endif + [Collection(nameof(SqlitePersistenceSpec))] + public class SqliteSnapshotStoreSaveSnapshotSpec: SnapshotStoreSaveSnapshotSpecBase + { + public SqliteSnapshotStoreSaveSnapshotSpec(ITestOutputHelper output, SqliteContainer fixture) + : base(Configuration(fixture), nameof(SqliteSnapshotStoreSaveSnapshotSpec), output) + { + } + + private static Configuration.Config Configuration(SqliteContainer fixture) + => SqliteSnapshotSpecConfig.Create(fixture); + + } +}