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);
+
+ }
+}