From 44ba61e4a5aad56254ae30716dfe273ea9b8b8d6 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Mon, 9 Jun 2025 17:24:39 +0100 Subject: [PATCH 1/6] Adjustments to avoid sqlite "database is locked" errors (#333) * add new exception test * Make memory tests and file path tests be explicit * set the default write parallelism to 1 * set to single reader for caching channel * format * Try to have consistent DB locked error test * always a single reader of the channel * Remove extra snapshot * Revert "Try to have consistent DB locked error test" This reverts commit 93669c57a3c07b18958d3058e0d622041b1c5132. * remove extra test that doesn't do anything --- .../Serialization/ChannelSaver.cs | 8 +- .../SQLite/SQLiteJsonCacheManager.cs | 27 ++++-- .../SQLite/SqLiteJsonCacheManagerFactory.cs | 3 +- .../Serialisation/V2/Send/SerializeProcess.cs | 8 +- .../V2/SerializeProcessFactory.cs | 14 +-- .../DetachedTests.cs | 6 +- .../ExceptionTests.cs | 4 +- .../SerializationTests.cs | 88 ++++++++++--------- .../SQLite/SQLiteJsonCacheManagerTests.cs | 16 ++-- 9 files changed, 94 insertions(+), 80 deletions(-) diff --git a/src/Speckle.Sdk.Dependencies/Serialization/ChannelSaver.cs b/src/Speckle.Sdk.Dependencies/Serialization/ChannelSaver.cs index 89bd97f7..37d1b999 100644 --- a/src/Speckle.Sdk.Dependencies/Serialization/ChannelSaver.cs +++ b/src/Speckle.Sdk.Dependencies/Serialization/ChannelSaver.cs @@ -13,8 +13,8 @@ public abstract class ChannelSaver private static readonly TimeSpan HTTP_BATCH_TIMEOUT = TimeSpan.FromSeconds(2); private const int MAX_PARALLELISM_HTTP = 4; private const int HTTP_CAPACITY = 500; - private const int MAX_CACHE_WRITE_PARALLELISM = 4; - private const int MAX_CACHE_BATCH = 500; + private const int MAX_CACHE_WRITE_PARALLELISM = 1; + private const int MAX_CACHE_BATCH = 1000; private readonly Channel _checkCacheChannel = Channel.CreateBounded( new BoundedChannelOptions(SEND_CAPACITY) @@ -45,9 +45,9 @@ public abstract class ChannelSaver cancellationToken ) .Join() - .Batch(cacheBatchSize ?? MAX_CACHE_BATCH) + .Batch(cacheBatchSize ?? MAX_CACHE_BATCH, singleReader: true) .WithTimeout(HTTP_BATCH_TIMEOUT) - .ReadAllConcurrently(maxParallelism ?? MAX_CACHE_WRITE_PARALLELISM, SaveToCache, cancellationToken) + .ReadAllConcurrently(MAX_CACHE_WRITE_PARALLELISM, SaveToCache, cancellationToken) .ContinueWith( t => { diff --git a/src/Speckle.Sdk/SQLite/SQLiteJsonCacheManager.cs b/src/Speckle.Sdk/SQLite/SQLiteJsonCacheManager.cs index a2a39c4b..0c3d89f7 100644 --- a/src/Speckle.Sdk/SQLite/SQLiteJsonCacheManager.cs +++ b/src/Speckle.Sdk/SQLite/SQLiteJsonCacheManager.cs @@ -13,7 +13,26 @@ public sealed class SqLiteJsonCacheManager : ISqLiteJsonCacheManager { private readonly CacheDbCommandPool _pool; - public SqLiteJsonCacheManager(string path, int concurrency) + public static ISqLiteJsonCacheManager FromMemory(int concurrency) => new SqLiteJsonCacheManager(concurrency); + + private SqLiteJsonCacheManager(int concurrency) + { + //disable pooling as we pool ourselves + var builder = new SqliteConnectionStringBuilder + { + Pooling = false, + DataSource = ":memory:", + Cache = SqliteCacheMode.Shared, + Mode = SqliteOpenMode.Memory, + }; + _pool = new CacheDbCommandPool(builder.ToString(), concurrency); + Initialize(); + } + + public static ISqLiteJsonCacheManager FromFilePath(string path, int concurrency) => + new SqLiteJsonCacheManager(path, concurrency); + + private SqLiteJsonCacheManager(string path, int concurrency) { //disable pooling as we pool ourselves var builder = new SqliteConnectionStringBuilder { Pooling = false, DataSource = path }; @@ -47,12 +66,6 @@ public sealed class SqLiteJsonCacheManager : ISqLiteJsonCacheManager command.ExecuteNonQuery(); } - // Insert Optimisations - - //Note / Hack: This setting has the potential to corrupt the db. - //cmd = new SqliteCommand("PRAGMA synchronous=OFF;", Connection); - //cmd.ExecuteNonQuery(); - using (SqliteCommand cmd1 = new("PRAGMA count_changes=OFF;", c)) { cmd1.ExecuteNonQuery(); diff --git a/src/Speckle.Sdk/SQLite/SqLiteJsonCacheManagerFactory.cs b/src/Speckle.Sdk/SQLite/SqLiteJsonCacheManagerFactory.cs index f8fedca4..9eddb021 100644 --- a/src/Speckle.Sdk/SQLite/SqLiteJsonCacheManagerFactory.cs +++ b/src/Speckle.Sdk/SQLite/SqLiteJsonCacheManagerFactory.cs @@ -9,7 +9,8 @@ public class SqLiteJsonCacheManagerFactory : ISqLiteJsonCacheManagerFactory { public const int INITIAL_CONCURRENCY = 4; - private ISqLiteJsonCacheManager Create(string path, int concurrency) => new SqLiteJsonCacheManager(path, concurrency); + private ISqLiteJsonCacheManager Create(string path, int concurrency) => + SqLiteJsonCacheManager.FromFilePath(path, concurrency); public ISqLiteJsonCacheManager CreateForUser(string scope) => Create(Path.Combine(SpecklePathProvider.UserApplicationDataPath(), "Speckle", $"{scope}.db"), 1); diff --git a/src/Speckle.Sdk/Serialisation/V2/Send/SerializeProcess.cs b/src/Speckle.Sdk/Serialisation/V2/Send/SerializeProcess.cs index 5fb03f69..0254921d 100644 --- a/src/Speckle.Sdk/Serialisation/V2/Send/SerializeProcess.cs +++ b/src/Speckle.Sdk/Serialisation/V2/Send/SerializeProcess.cs @@ -16,8 +16,8 @@ public record SerializeProcessOptions( bool SkipFindTotalObjects = false ) { - public int? MaxHttpSendSize { get; set; } - public int? MaxCacheSize { get; set; } + public int? MaxHttpSendBatchSize { get; set; } + public int? MaxCacheBatchSize { get; set; } public int? MaxParallelism { get; set; } } @@ -112,8 +112,8 @@ public sealed class SerializeProcess( { var channelTask = objectSaver.Start( options?.MaxParallelism, - options?.MaxHttpSendSize, - options?.MaxCacheSize, + options?.MaxHttpSendBatchSize, + options?.MaxCacheBatchSize, _processSource.Token ); var findTotalObjectsTask = Task.CompletedTask; diff --git a/src/Speckle.Sdk/Serialisation/V2/SerializeProcessFactory.cs b/src/Speckle.Sdk/Serialisation/V2/SerializeProcessFactory.cs index 550cfa4b..c1428bf9 100644 --- a/src/Speckle.Sdk/Serialisation/V2/SerializeProcessFactory.cs +++ b/src/Speckle.Sdk/Serialisation/V2/SerializeProcessFactory.cs @@ -64,18 +64,10 @@ public class SerializeProcessFactory( #pragma warning disable CA2000 var memoryJsonCacheManager = new MemoryJsonCacheManager(jsonCache); #pragma warning restore CA2000 - return new SerializeProcess( + return CreateSerializeProcess( + memoryJsonCacheManager, + new MemoryServerObjectManager(objects), progress, - new ObjectSaver( - progress, - memoryJsonCacheManager, - new MemoryServerObjectManager(objects), - loggerFactory.CreateLogger(), - cancellationToken - ), - baseChildFinder, - new BaseSerializer(memoryJsonCacheManager, objectSerializerFactory), - loggerFactory, cancellationToken, options ); diff --git a/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs b/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs index 8b278d59..a8664172 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs @@ -123,7 +123,7 @@ public class DetachedTests objects, null, default, - new SerializeProcessOptions(false, false, true, true) { MaxParallelism = 1, MaxHttpSendSize = 1 } + new SerializeProcessOptions(false, false, true, true) { MaxParallelism = 1, MaxHttpSendBatchSize = 1 } ); var results = await serializeProcess.Serialize(@base); @@ -150,7 +150,7 @@ public class DetachedTests objects, null, default, - new SerializeProcessOptions(false, false, true, true) { MaxParallelism = 1, MaxHttpSendSize = 1 } + new SerializeProcessOptions(false, false, true, true) { MaxParallelism = 1, MaxHttpSendBatchSize = 1 } ); var results = await serializeProcess.Serialize(@base); @@ -172,7 +172,7 @@ public class DetachedTests objects, null, default, - new SerializeProcessOptions(false, false, true, true) { MaxParallelism = 1, MaxHttpSendSize = 1 } + new SerializeProcessOptions(false, false, true, true) { MaxParallelism = 1, MaxHttpSendBatchSize = 1 } ); var results = await serializeProcess.Serialize(@base); diff --git a/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.cs b/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.cs index ca58b036..a377d640 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.cs @@ -95,8 +95,8 @@ public class ExceptionTests default, new SerializeProcessOptions(false, false, false, true) { - MaxHttpSendSize = 1, - MaxCacheSize = 1, + MaxHttpSendBatchSize = 1, + MaxCacheBatchSize = 1, MaxParallelism = 1, } ); diff --git a/tests/Speckle.Sdk.Serialization.Tests/SerializationTests.cs b/tests/Speckle.Sdk.Serialization.Tests/SerializationTests.cs index 318b7125..f2b3bc6a 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/SerializationTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/SerializationTests.cs @@ -14,6 +14,7 @@ using Speckle.Sdk.Serialisation.V2; using Speckle.Sdk.Serialisation.V2.Receive; using Speckle.Sdk.Serialisation.V2.Send; using Speckle.Sdk.Serialization.Tests.Framework; +using Speckle.Sdk.SQLite; using Speckle.Sdk.Testing.Framework; namespace Speckle.Sdk.Serialization.Tests; @@ -50,45 +51,45 @@ public class SerializationTests public void Dispose() { } } - [Theory] - [InlineData("RevitObject.json.gz")] - public async Task Basic_Namespace_Validation(string fileName) - { - var closures = TestFileManager.GetFileAsClosures(fileName); - var deserializer = new SpeckleObjectDeserializer + /* [Theory] + [InlineData("RevitObject.json.gz")] + public async Task Basic_Namespace_Validation(string fileName) { - ReadTransport = new TestTransport(closures), - CancellationToken = default, - }; - - foreach (var (id, objJson) in closures) - { - var jObject = JObject.Parse(objJson); - var oldSpeckleType = jObject["speckle_type"].NotNull().Value().NotNull(); - var starts = oldSpeckleType.StartsWith("Speckle.Core.") || oldSpeckleType.StartsWith("Objects."); - starts.Should().BeTrue($"{oldSpeckleType} isn't expected"); - - var baseType = await deserializer.DeserializeAsync(objJson); - baseType.id.Should().Be(id); - - var oldType = TypeLoader.GetAtomicType(oldSpeckleType); - if (oldType == typeof(Base)) + var closures = TestFileManager.GetFileAsClosures(fileName); + var deserializer = new SpeckleObjectDeserializer { - oldSpeckleType.Should().NotContain("Base"); - } - else + ReadTransport = new TestTransport(closures), + CancellationToken = default, + }; + + foreach (var (id, objJson) in closures) { - starts = baseType.speckle_type.StartsWith("Speckle.Core.") || baseType.speckle_type.StartsWith("Objects."); - starts.Should().BeTrue($"{baseType.speckle_type} isn't expected"); - - var type = TypeLoader.GetAtomicType(baseType.speckle_type); - type.Should().NotBeNull(); - var name = TypeLoader.GetTypeString(type) ?? throw new ArgumentNullException($"Could not find: {type}"); - starts = name.StartsWith("Speckle.Core") || name.StartsWith("Objects"); - starts.Should().BeTrue($"{name} isn't expected"); + var jObject = JObject.Parse(objJson); + var oldSpeckleType = jObject["speckle_type"].NotNull().Value().NotNull(); + var starts = oldSpeckleType.StartsWith("Speckle.Core.") || oldSpeckleType.StartsWith("Objects."); + starts.Should().BeTrue($"{oldSpeckleType} isn't expected"); + + var baseType = await deserializer.DeserializeAsync(objJson); + baseType.id.Should().Be(id); + + var oldType = TypeLoader.GetAtomicType(oldSpeckleType); + if (oldType == typeof(Base)) + { + oldSpeckleType.Should().NotContain("Base"); + } + else + { + starts = baseType.speckle_type.StartsWith("Speckle.Core.") || baseType.speckle_type.StartsWith("Objects."); + starts.Should().BeTrue($"{baseType.speckle_type} isn't expected"); + + var type = TypeLoader.GetAtomicType(baseType.speckle_type); + type.Should().NotBeNull(); + var name = TypeLoader.GetTypeString(type) ?? throw new ArgumentNullException($"Could not find: {type}"); + starts = name.StartsWith("Speckle.Core") || name.StartsWith("Objects"); + starts.Should().BeTrue($"{name} isn't expected"); + } } - } - } + }*/ [Theory] [InlineData("RevitObject.json.gz")] @@ -184,9 +185,16 @@ public class SerializationTests } [Theory] - [InlineData("RevitObject.json.gz", "3416d3fe01c9196115514c4a2f41617b", 7818, 4674)] - public async Task Roundtrip_Test_New(string fileName, string rootId, int oldCount, int newCount) + [InlineData(1)] + [InlineData(2)] + [InlineData(3)] + [InlineData(4)] + public async Task Roundtrip_Test_New(int concurrency) { + string fileName = "RevitObject.json.gz"; + string rootId = "3416d3fe01c9196115514c4a2f41617b"; + int oldCount = 7818; + int newCount = 4674; var closures = TestFileManager.GetFileAsClosures(fileName); closures.Count.Should().Be(oldCount); @@ -218,11 +226,11 @@ public class SerializationTests await using ( var serializeProcess = _factory.CreateSerializeProcess( - new ConcurrentDictionary(), - newIdToJson, + SqLiteJsonCacheManager.FromMemory(1), + new MemoryServerObjectManager(newIdToJson), null, default, - new SerializeProcessOptions(true, true, false, true) + new SerializeProcessOptions(false, false, false, true) { MaxCacheBatchSize = 1, MaxParallelism = concurrency } ) ) { diff --git a/tests/Speckle.Sdk.Tests.Unit/SQLite/SQLiteJsonCacheManagerTests.cs b/tests/Speckle.Sdk.Tests.Unit/SQLite/SQLiteJsonCacheManagerTests.cs index 7dfb71f2..e97cdd8d 100644 --- a/tests/Speckle.Sdk.Tests.Unit/SQLite/SQLiteJsonCacheManagerTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/SQLite/SQLiteJsonCacheManagerTests.cs @@ -22,7 +22,7 @@ public class SQLiteJsonCacheManagerTests : IDisposable public void TestGetAll() { var data = new List<(string id, string json)>() { ("id1", "1"), ("id2", "2") }; - using var manager = new SqLiteJsonCacheManager(_basePath, 2); + using var manager = SqLiteJsonCacheManager.FromFilePath(_basePath, 2); manager.SaveObjects(data); var items = manager.GetAllObjects(); items.Count.Should().Be(data.Count); @@ -38,7 +38,7 @@ public class SQLiteJsonCacheManagerTests : IDisposable public void TestGet() { var data = new List<(string id, string json)>() { ("id1", "1"), ("id2", "2") }; - using var manager = new SqLiteJsonCacheManager(_basePath, 2); + using var manager = SqLiteJsonCacheManager.FromFilePath(_basePath, 2); foreach (var d in data) { manager.SaveObject(d.id, d.json); @@ -84,7 +84,7 @@ public class SQLiteJsonCacheManagerTests : IDisposable public void TestLargeJsonPayload() { var largeJson = new string('a', 100_000); - using var manager = new SqLiteJsonCacheManager(_basePath, 2); + using var manager = SqLiteJsonCacheManager.FromFilePath(_basePath, 2); manager.SaveObject("large", largeJson); var result = manager.GetObject("large"); result.Should().Be(largeJson); @@ -96,7 +96,7 @@ public class SQLiteJsonCacheManagerTests : IDisposable var id = "spécial_字符_!@#$%^&*()"; var json = /*lang=json,strict*/ "{\"value\": \"特殊字符!@#$%^&*()\"}"; - using var manager = new SqLiteJsonCacheManager(_basePath, 2); + using var manager = SqLiteJsonCacheManager.FromFilePath(_basePath, 2); manager.SaveObject(id, json); var result = manager.GetObject(id); result.Should().Be(json); @@ -108,7 +108,7 @@ public class SQLiteJsonCacheManagerTests : IDisposable [Fact] public void TestBulkInsertEmptyCollection() { - using var manager = new SqLiteJsonCacheManager(_basePath, 2); + using var manager = SqLiteJsonCacheManager.FromFilePath(_basePath, 2); manager.SaveObjects(new List<(string, string)>()); manager.GetAllObjects().Count.Should().Be(0); } @@ -116,7 +116,7 @@ public class SQLiteJsonCacheManagerTests : IDisposable [Fact] public void TestRepeatedUpdateAndDelete() { - using var manager = new SqLiteJsonCacheManager(_basePath, 2); + using var manager = SqLiteJsonCacheManager.FromFilePath(_basePath, 2); manager.SaveObject("id", "1"); manager.UpdateObject("id", "2"); manager.UpdateObject("id", "3"); @@ -129,7 +129,7 @@ public class SQLiteJsonCacheManagerTests : IDisposable [Fact] public void TestGetAndDeleteNonExistentId() { - using var manager = new SqLiteJsonCacheManager(_basePath, 2); + using var manager = SqLiteJsonCacheManager.FromFilePath(_basePath, 2); manager.GetObject("doesnotexist").Should().BeNull(); manager.HasObject("doesnotexist").Should().BeFalse(); manager.DeleteObject("doesnotexist"); // Should not throw @@ -138,7 +138,7 @@ public class SQLiteJsonCacheManagerTests : IDisposable [Fact] public void TestNullOrEmptyInput() { - using var manager = new SqLiteJsonCacheManager(_basePath, 2); + using var manager = SqLiteJsonCacheManager.FromFilePath(_basePath, 2); // Empty id Assert.Throws(() => manager.SaveObject("", "emptyid")); // Empty json From 7f8b59d348da4c5f6d1ae88f7a252b5dc87f5c37 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 10 Jun 2025 11:15:01 +0100 Subject: [PATCH 2/6] Pool object savers instead of sqlite --- .../SQLite/SQLiteJsonCacheManager.cs | 8 +++-- .../V2/MemoryJsonCacheManager.cs | 4 +++ .../V2/Send/ObjectSaverFactory.cs | 36 +++++++++++++++++++ .../Serialisation/V2/Send/SerializeProcess.cs | 1 - .../V2/SerializeProcessFactory.cs | 11 ++---- src/Speckle.Sdk/ServiceRegistration.cs | 2 ++ .../DetachedTests.cs | 3 ++ .../DummyCancellationSqLiteSendManager.cs | 3 ++ .../Framework/ExceptionSendCacheManager.cs | 3 ++ .../Framework/DummySqLiteReceiveManager.cs | 3 ++ .../Framework/DummySqLiteSendManager.cs | 3 ++ 11 files changed, 66 insertions(+), 11 deletions(-) create mode 100644 src/Speckle.Sdk/Serialisation/V2/Send/ObjectSaverFactory.cs diff --git a/src/Speckle.Sdk/SQLite/SQLiteJsonCacheManager.cs b/src/Speckle.Sdk/SQLite/SQLiteJsonCacheManager.cs index 0c3d89f7..dfb4322a 100644 --- a/src/Speckle.Sdk/SQLite/SQLiteJsonCacheManager.cs +++ b/src/Speckle.Sdk/SQLite/SQLiteJsonCacheManager.cs @@ -12,16 +12,19 @@ public partial interface ISqLiteJsonCacheManager : IDisposable; public sealed class SqLiteJsonCacheManager : ISqLiteJsonCacheManager { private readonly CacheDbCommandPool _pool; + + public string Path {get;} public static ISqLiteJsonCacheManager FromMemory(int concurrency) => new SqLiteJsonCacheManager(concurrency); private SqLiteJsonCacheManager(int concurrency) { + Path = ":memory:"; //disable pooling as we pool ourselves var builder = new SqliteConnectionStringBuilder { Pooling = false, - DataSource = ":memory:", + DataSource = Path, Cache = SqliteCacheMode.Shared, Mode = SqliteOpenMode.Memory, }; @@ -34,8 +37,9 @@ public sealed class SqLiteJsonCacheManager : ISqLiteJsonCacheManager private SqLiteJsonCacheManager(string path, int concurrency) { + Path = path; //disable pooling as we pool ourselves - var builder = new SqliteConnectionStringBuilder { Pooling = false, DataSource = path }; + var builder = new SqliteConnectionStringBuilder { Pooling = false, DataSource = Path }; _pool = new CacheDbCommandPool(builder.ToString(), concurrency); Initialize(); } diff --git a/src/Speckle.Sdk/Serialisation/V2/MemoryJsonCacheManager.cs b/src/Speckle.Sdk/Serialisation/V2/MemoryJsonCacheManager.cs index 26e142be..447c3ce9 100644 --- a/src/Speckle.Sdk/Serialisation/V2/MemoryJsonCacheManager.cs +++ b/src/Speckle.Sdk/Serialisation/V2/MemoryJsonCacheManager.cs @@ -7,6 +7,10 @@ namespace Speckle.Sdk.Serialisation.V2; public class MemoryJsonCacheManager(ConcurrentDictionary jsonCache) : ISqLiteJsonCacheManager #pragma warning restore CA1063 { +#pragma warning disable CA1065 + public string Path => throw new NotImplementedException(); +#pragma warning restore CA1065 + public IReadOnlyCollection<(string Id, string Json)> GetAllObjects() => jsonCache.Select(x => (x.Key.Value, x.Value.Value)).ToList(); diff --git a/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSaverFactory.cs b/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSaverFactory.cs new file mode 100644 index 00000000..8988f492 --- /dev/null +++ b/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSaverFactory.cs @@ -0,0 +1,36 @@ +using System.Collections.Concurrent; +using Microsoft.Extensions.Logging; +using Speckle.InterfaceGenerator; +using Speckle.Sdk.SQLite; +using Speckle.Sdk.Transports; + +namespace Speckle.Sdk.Serialisation.V2.Send; + +public partial interface IObjectSaverFactory : IDisposable; +[GenerateAutoInterface] +public sealed class ObjectSaverFactory( IServerObjectManager serverObjectManager, ILoggerFactory loggerFactory) : IObjectSaverFactory +{private readonly ConcurrentDictionary _savers = new(); + public IObjectSaver Create( + ISqLiteJsonCacheManager sqLiteJsonCacheManager, IProgress? progress, CancellationToken cancellationToken, + SerializeProcessOptions? options = null) + { + if (!_savers.TryGetValue(sqLiteJsonCacheManager.Path, out var saver)) + { + saver = new ObjectSaver(progress,sqLiteJsonCacheManager, serverObjectManager, loggerFactory.CreateLogger(), + cancellationToken, options); + _savers.TryAdd(sqLiteJsonCacheManager.Path, saver); + } + + return saver; + } + [AutoInterfaceIgnore] + public void Dispose() + { + foreach (var pool in _savers) + { + pool.Value.Dispose(); + } + + _savers.Clear(); + } +} diff --git a/src/Speckle.Sdk/Serialisation/V2/Send/SerializeProcess.cs b/src/Speckle.Sdk/Serialisation/V2/Send/SerializeProcess.cs index 0254921d..35cb3731 100644 --- a/src/Speckle.Sdk/Serialisation/V2/Send/SerializeProcess.cs +++ b/src/Speckle.Sdk/Serialisation/V2/Send/SerializeProcess.cs @@ -86,7 +86,6 @@ public sealed class SerializeProcess( await WaitForSchedulerCompletion().ConfigureAwait(false); await _highest.DisposeAsync().ConfigureAwait(false); await _belowNormal.DisposeAsync().ConfigureAwait(false); - objectSaver.Dispose(); _processSource.Dispose(); } diff --git a/src/Speckle.Sdk/Serialisation/V2/SerializeProcessFactory.cs b/src/Speckle.Sdk/Serialisation/V2/SerializeProcessFactory.cs index c1428bf9..3e0a489e 100644 --- a/src/Speckle.Sdk/Serialisation/V2/SerializeProcessFactory.cs +++ b/src/Speckle.Sdk/Serialisation/V2/SerializeProcessFactory.cs @@ -13,6 +13,7 @@ public class SerializeProcessFactory( IObjectSerializerFactory objectSerializerFactory, ISqLiteJsonCacheManagerFactory sqLiteJsonCacheManagerFactory, IServerObjectManagerFactory serverObjectManagerFactory, + IObjectSaverFactory objectSaverFactory, ILoggerFactory loggerFactory ) : ISerializeProcessFactory { @@ -27,7 +28,7 @@ public class SerializeProcessFactory( { var sqLiteJsonCacheManager = sqLiteJsonCacheManagerFactory.CreateFromStream(streamId); var serverObjectManager = serverObjectManagerFactory.Create(url, streamId, authorizationToken); - return CreateSerializeProcess(sqLiteJsonCacheManager, serverObjectManager, progress, cancellationToken, options); + return CreateSerializeProcess(sqLiteJsonCacheManager, serverObjectManager, progress, cancellationToken, options); } public ISerializeProcess CreateSerializeProcess( @@ -39,13 +40,7 @@ public class SerializeProcessFactory( ) => new SerializeProcess( progress, - new ObjectSaver( - progress, - sqLiteJsonCacheManager, - serverObjectManager, - loggerFactory.CreateLogger(), - cancellationToken - ), + objectSaverFactory.Create(sqLiteJsonCacheManager, progress, cancellationToken, options), baseChildFinder, new BaseSerializer(sqLiteJsonCacheManager, objectSerializerFactory), loggerFactory, diff --git a/src/Speckle.Sdk/ServiceRegistration.cs b/src/Speckle.Sdk/ServiceRegistration.cs index 8f8066ae..106be8bd 100644 --- a/src/Speckle.Sdk/ServiceRegistration.cs +++ b/src/Speckle.Sdk/ServiceRegistration.cs @@ -97,6 +97,8 @@ public static class ServiceRegistration typeof(Client) ); serviceCollection.AddMatchingInterfacesAsTransient(typeof(GraphQLRetry).Assembly); + //we want to make object savers be singletons per stream so needs a singleton factory + serviceCollection.AddSingleton(); return serviceCollection; } diff --git a/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs b/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs index a8664172..6df010aa 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs @@ -373,6 +373,9 @@ public class DummyServerObjectManager : IServerObjectManager public class DummySendCacheManager(Dictionary objects) : ISqLiteJsonCacheManager { +#pragma warning disable CA1065 + public string Path => throw new NotImplementedException(); +#pragma warning restore CA1065 public void Dispose() { } public IReadOnlyCollection<(string, string)> GetAllObjects() => throw new NotImplementedException(); diff --git a/tests/Speckle.Sdk.Serialization.Tests/DummyCancellationSqLiteSendManager.cs b/tests/Speckle.Sdk.Serialization.Tests/DummyCancellationSqLiteSendManager.cs index 2d6ca588..1244b303 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/DummyCancellationSqLiteSendManager.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/DummyCancellationSqLiteSendManager.cs @@ -4,6 +4,9 @@ namespace Speckle.Sdk.Serialization.Tests; public class DummyCancellationSqLiteSendManager : ISqLiteJsonCacheManager { +#pragma warning disable CA1065 + public string Path => throw new NotImplementedException(); +#pragma warning restore CA1065 public string? GetObject(string id) => null; public void SaveObject(string id, string json) => throw new NotImplementedException(); diff --git a/tests/Speckle.Sdk.Serialization.Tests/Framework/ExceptionSendCacheManager.cs b/tests/Speckle.Sdk.Serialization.Tests/Framework/ExceptionSendCacheManager.cs index 5572aa02..22e5372e 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/Framework/ExceptionSendCacheManager.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/Framework/ExceptionSendCacheManager.cs @@ -4,6 +4,9 @@ namespace Speckle.Sdk.Serialization.Tests.Framework; public class ExceptionSendCacheManager(bool? hasObject = null, int? exceptionsAfter = null) : ISqLiteJsonCacheManager { +#pragma warning disable CA1065 + public string Path => throw new NotImplementedException(); +#pragma warning restore CA1065 private readonly object _lock = new(); private int _count; diff --git a/tests/Speckle.Sdk.Testing/Framework/DummySqLiteReceiveManager.cs b/tests/Speckle.Sdk.Testing/Framework/DummySqLiteReceiveManager.cs index fcfe6832..01109410 100644 --- a/tests/Speckle.Sdk.Testing/Framework/DummySqLiteReceiveManager.cs +++ b/tests/Speckle.Sdk.Testing/Framework/DummySqLiteReceiveManager.cs @@ -5,6 +5,9 @@ namespace Speckle.Sdk.Testing.Framework; public sealed class DummySqLiteReceiveManager(IReadOnlyDictionary savedObjects) : ISqLiteJsonCacheManager { +#pragma warning disable CA1065 + public string Path => throw new NotImplementedException(); +#pragma warning restore CA1065 public void Dispose() { } public IReadOnlyCollection<(string, string)> GetAllObjects() => throw new NotImplementedException(); diff --git a/tests/Speckle.Sdk.Testing/Framework/DummySqLiteSendManager.cs b/tests/Speckle.Sdk.Testing/Framework/DummySqLiteSendManager.cs index b1425dd6..63983aa6 100644 --- a/tests/Speckle.Sdk.Testing/Framework/DummySqLiteSendManager.cs +++ b/tests/Speckle.Sdk.Testing/Framework/DummySqLiteSendManager.cs @@ -4,6 +4,9 @@ namespace Speckle.Sdk.Testing.Framework; public class DummySqLiteSendManager : ISqLiteJsonCacheManager { +#pragma warning disable CA1065 + public string Path => throw new NotImplementedException(); +#pragma warning restore CA1065 public string? GetObject(string id) => throw new NotImplementedException(); public void SaveObject(string id, string json) => throw new NotImplementedException(); From bc81c21e9d61c3cfdb1246327cad379b48b775b2 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 10 Jun 2025 11:15:30 +0100 Subject: [PATCH 3/6] format --- .../SQLite/SQLiteJsonCacheManager.cs | 6 ++--- .../V2/Send/ObjectSaverFactory.cs | 26 ++++++++++++++----- .../V2/SerializeProcessFactory.cs | 2 +- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/Speckle.Sdk/SQLite/SQLiteJsonCacheManager.cs b/src/Speckle.Sdk/SQLite/SQLiteJsonCacheManager.cs index dfb4322a..b08a83ed 100644 --- a/src/Speckle.Sdk/SQLite/SQLiteJsonCacheManager.cs +++ b/src/Speckle.Sdk/SQLite/SQLiteJsonCacheManager.cs @@ -12,14 +12,14 @@ public partial interface ISqLiteJsonCacheManager : IDisposable; public sealed class SqLiteJsonCacheManager : ISqLiteJsonCacheManager { private readonly CacheDbCommandPool _pool; - - public string Path {get;} + + public string Path { get; } public static ISqLiteJsonCacheManager FromMemory(int concurrency) => new SqLiteJsonCacheManager(concurrency); private SqLiteJsonCacheManager(int concurrency) { - Path = ":memory:"; + Path = ":memory:"; //disable pooling as we pool ourselves var builder = new SqliteConnectionStringBuilder { diff --git a/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSaverFactory.cs b/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSaverFactory.cs index 8988f492..474037ab 100644 --- a/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSaverFactory.cs +++ b/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSaverFactory.cs @@ -7,22 +7,36 @@ using Speckle.Sdk.Transports; namespace Speckle.Sdk.Serialisation.V2.Send; public partial interface IObjectSaverFactory : IDisposable; + [GenerateAutoInterface] -public sealed class ObjectSaverFactory( IServerObjectManager serverObjectManager, ILoggerFactory loggerFactory) : IObjectSaverFactory -{private readonly ConcurrentDictionary _savers = new(); +public sealed class ObjectSaverFactory(IServerObjectManager serverObjectManager, ILoggerFactory loggerFactory) + : IObjectSaverFactory +{ + private readonly ConcurrentDictionary _savers = new(); + public IObjectSaver Create( - ISqLiteJsonCacheManager sqLiteJsonCacheManager, IProgress? progress, CancellationToken cancellationToken, - SerializeProcessOptions? options = null) + ISqLiteJsonCacheManager sqLiteJsonCacheManager, + IProgress? progress, + CancellationToken cancellationToken, + SerializeProcessOptions? options = null + ) { if (!_savers.TryGetValue(sqLiteJsonCacheManager.Path, out var saver)) { - saver = new ObjectSaver(progress,sqLiteJsonCacheManager, serverObjectManager, loggerFactory.CreateLogger(), - cancellationToken, options); + saver = new ObjectSaver( + progress, + sqLiteJsonCacheManager, + serverObjectManager, + loggerFactory.CreateLogger(), + cancellationToken, + options + ); _savers.TryAdd(sqLiteJsonCacheManager.Path, saver); } return saver; } + [AutoInterfaceIgnore] public void Dispose() { diff --git a/src/Speckle.Sdk/Serialisation/V2/SerializeProcessFactory.cs b/src/Speckle.Sdk/Serialisation/V2/SerializeProcessFactory.cs index 3e0a489e..f031d715 100644 --- a/src/Speckle.Sdk/Serialisation/V2/SerializeProcessFactory.cs +++ b/src/Speckle.Sdk/Serialisation/V2/SerializeProcessFactory.cs @@ -28,7 +28,7 @@ public class SerializeProcessFactory( { var sqLiteJsonCacheManager = sqLiteJsonCacheManagerFactory.CreateFromStream(streamId); var serverObjectManager = serverObjectManagerFactory.Create(url, streamId, authorizationToken); - return CreateSerializeProcess(sqLiteJsonCacheManager, serverObjectManager, progress, cancellationToken, options); + return CreateSerializeProcess(sqLiteJsonCacheManager, serverObjectManager, progress, cancellationToken, options); } public ISerializeProcess CreateSerializeProcess( From 0e33e8df8f183757a768300353d823b49f024f20 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 10 Jun 2025 11:33:17 +0100 Subject: [PATCH 4/6] add tests --- .../ObjectSaverFactoryTests.cs | 77 +++++++++++++++++++ tests/Speckle.Sdk.Testing/MoqTest.cs | 2 +- 2 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 tests/Speckle.Sdk.Serialization.Tests/ObjectSaverFactoryTests.cs diff --git a/tests/Speckle.Sdk.Serialization.Tests/ObjectSaverFactoryTests.cs b/tests/Speckle.Sdk.Serialization.Tests/ObjectSaverFactoryTests.cs new file mode 100644 index 00000000..5f21e7b1 --- /dev/null +++ b/tests/Speckle.Sdk.Serialization.Tests/ObjectSaverFactoryTests.cs @@ -0,0 +1,77 @@ +using FluentAssertions; +using Microsoft.Extensions.Logging; +using Moq; +using Speckle.Sdk.SQLite; +using Speckle.Sdk.Testing; + +namespace Speckle.Sdk.Serialisation.V2.Send.Tests; + +public class ObjectSaverFactoryTests : MoqTest +{ + private readonly Mock _serverObjectManagerMock; + private readonly Mock _loggerFactoryMock; + private readonly Mock> _loggerMock; + private readonly ObjectSaverFactory _factory; + + public ObjectSaverFactoryTests() + { + _serverObjectManagerMock = Create(); + _loggerFactoryMock = Create(); + _loggerMock = Create>(); + _factory = new ObjectSaverFactory(_serverObjectManagerMock.Object, _loggerFactoryMock.Object); + } + + public override void Dispose() + { + _factory.Dispose(); + base.Dispose(); + } + + [Fact] + public void Create_ShouldReturnObjectSaverInstance() + { + _loggerFactoryMock.Setup(f => f.CreateLogger(typeof(ObjectSaver).FullName)).Returns(_loggerMock.Object); + var cacheManagerMock = Create(); + cacheManagerMock.Setup(x => x.Dispose()); + cacheManagerMock.SetupGet(c => c.Path).Returns("/tmp/test1.db"); + + var saver = _factory.Create(cacheManagerMock.Object, null, CancellationToken.None); + + saver.Should().NotBeNull(); + } + + [Fact] + public void Create_ShouldReturnSameInstanceForSamePath() + { + _loggerFactoryMock.Setup(f => f.CreateLogger(typeof(ObjectSaver).FullName)).Returns(_loggerMock.Object); + var cacheManagerMock = Create(); + cacheManagerMock.Setup(x => x.Dispose()); + cacheManagerMock.SetupGet(c => c.Path).Returns("/tmp/test2.db"); + + var saver1 = _factory.Create(cacheManagerMock.Object, null, CancellationToken.None); + var saver2 = _factory.Create(cacheManagerMock.Object, null, CancellationToken.None); + + saver1.Should().BeSameAs(saver2); + } + + [Fact] + public void Dispose_ShouldDisposeAllSavers() + { + var saverMock1 = Create(); + _factory + .GetType() + .GetField("_savers", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance) + ?.SetValue( + _factory, + new System.Collections.Concurrent.ConcurrentDictionary( + new[] + { + new System.Collections.Generic.KeyValuePair("/tmp/test3.db", saverMock1.Object), + } + ) + ); + saverMock1.Setup(x => x.Dispose()); + + _factory.Dispose(); + } +} diff --git a/tests/Speckle.Sdk.Testing/MoqTest.cs b/tests/Speckle.Sdk.Testing/MoqTest.cs index 34e8391b..bc3ca8fa 100644 --- a/tests/Speckle.Sdk.Testing/MoqTest.cs +++ b/tests/Speckle.Sdk.Testing/MoqTest.cs @@ -8,7 +8,7 @@ public abstract class MoqTest : IDisposable { protected MoqTest() => Repository = new(MockBehavior.Strict); - public void Dispose() => Repository.VerifyAll(); + public virtual void Dispose() => Repository.VerifyAll(); protected MockRepository Repository { get; private set; } = new(MockBehavior.Strict); From 46c067308e54c488c1d9095657f0bea23c34c1ba Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 10 Jun 2025 11:39:42 +0100 Subject: [PATCH 5/6] Fix DI dependency and tests --- .../V2/Send/ObjectSaverFactory.cs | 4 +-- .../V2/SerializeProcessFactory.cs | 2 +- .../ObjectSaverFactoryTests.cs | 25 ++++++++++++++----- .../SerializeProcessRecordExceptionTests.cs | 3 --- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSaverFactory.cs b/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSaverFactory.cs index 474037ab..96ddbcb3 100644 --- a/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSaverFactory.cs +++ b/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSaverFactory.cs @@ -9,12 +9,12 @@ namespace Speckle.Sdk.Serialisation.V2.Send; public partial interface IObjectSaverFactory : IDisposable; [GenerateAutoInterface] -public sealed class ObjectSaverFactory(IServerObjectManager serverObjectManager, ILoggerFactory loggerFactory) - : IObjectSaverFactory +public sealed class ObjectSaverFactory(ILoggerFactory loggerFactory) : IObjectSaverFactory { private readonly ConcurrentDictionary _savers = new(); public IObjectSaver Create( + IServerObjectManager serverObjectManager, ISqLiteJsonCacheManager sqLiteJsonCacheManager, IProgress? progress, CancellationToken cancellationToken, diff --git a/src/Speckle.Sdk/Serialisation/V2/SerializeProcessFactory.cs b/src/Speckle.Sdk/Serialisation/V2/SerializeProcessFactory.cs index f031d715..2bb38bac 100644 --- a/src/Speckle.Sdk/Serialisation/V2/SerializeProcessFactory.cs +++ b/src/Speckle.Sdk/Serialisation/V2/SerializeProcessFactory.cs @@ -40,7 +40,7 @@ public class SerializeProcessFactory( ) => new SerializeProcess( progress, - objectSaverFactory.Create(sqLiteJsonCacheManager, progress, cancellationToken, options), + objectSaverFactory.Create(serverObjectManager, sqLiteJsonCacheManager, progress, cancellationToken, options), baseChildFinder, new BaseSerializer(sqLiteJsonCacheManager, objectSerializerFactory), loggerFactory, diff --git a/tests/Speckle.Sdk.Serialization.Tests/ObjectSaverFactoryTests.cs b/tests/Speckle.Sdk.Serialization.Tests/ObjectSaverFactoryTests.cs index 5f21e7b1..253c52a2 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/ObjectSaverFactoryTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/ObjectSaverFactoryTests.cs @@ -8,17 +8,15 @@ namespace Speckle.Sdk.Serialisation.V2.Send.Tests; public class ObjectSaverFactoryTests : MoqTest { - private readonly Mock _serverObjectManagerMock; private readonly Mock _loggerFactoryMock; private readonly Mock> _loggerMock; private readonly ObjectSaverFactory _factory; public ObjectSaverFactoryTests() { - _serverObjectManagerMock = Create(); _loggerFactoryMock = Create(); _loggerMock = Create>(); - _factory = new ObjectSaverFactory(_serverObjectManagerMock.Object, _loggerFactoryMock.Object); + _factory = new ObjectSaverFactory(_loggerFactoryMock.Object); } public override void Dispose() @@ -35,7 +33,12 @@ public class ObjectSaverFactoryTests : MoqTest cacheManagerMock.Setup(x => x.Dispose()); cacheManagerMock.SetupGet(c => c.Path).Returns("/tmp/test1.db"); - var saver = _factory.Create(cacheManagerMock.Object, null, CancellationToken.None); + var saver = _factory.Create( + Create().Object, + cacheManagerMock.Object, + null, + CancellationToken.None + ); saver.Should().NotBeNull(); } @@ -48,8 +51,18 @@ public class ObjectSaverFactoryTests : MoqTest cacheManagerMock.Setup(x => x.Dispose()); cacheManagerMock.SetupGet(c => c.Path).Returns("/tmp/test2.db"); - var saver1 = _factory.Create(cacheManagerMock.Object, null, CancellationToken.None); - var saver2 = _factory.Create(cacheManagerMock.Object, null, CancellationToken.None); + var saver1 = _factory.Create( + Create().Object, + cacheManagerMock.Object, + null, + CancellationToken.None + ); + var saver2 = _factory.Create( + Create().Object, + cacheManagerMock.Object, + null, + CancellationToken.None + ); saver1.Should().BeSameAs(saver2); } diff --git a/tests/Speckle.Sdk.Tests.Unit/Serialisation/SerializeProcessRecordExceptionTests.cs b/tests/Speckle.Sdk.Tests.Unit/Serialisation/SerializeProcessRecordExceptionTests.cs index 1e855dd7..a69a5f76 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Serialisation/SerializeProcessRecordExceptionTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Serialisation/SerializeProcessRecordExceptionTests.cs @@ -21,7 +21,6 @@ public class SerializeProcessRecordExceptionTests : MoqTest .Setup(f => f.CreateLogger("Speckle.Sdk.Serialisation.V2.PriorityScheduler")) .Returns(Create>().Object); var objectSaverMock = Create(); - objectSaverMock.Setup(x => x.Dispose()); var baseChildFinderMock = Create(); var baseSerializerMock = Create(); using var cts = new CancellationTokenSource(); @@ -57,7 +56,6 @@ public class SerializeProcessRecordExceptionTests : MoqTest .Setup(f => f.CreateLogger("Speckle.Sdk.Serialisation.V2.PriorityScheduler")) .Returns(Create>().Object); var objectSaverMock = Create(); - objectSaverMock.Setup(x => x.Dispose()); var baseChildFinderMock = Create(); var baseSerializerMock = Create(); using var cts = new CancellationTokenSource(); @@ -88,7 +86,6 @@ public class SerializeProcessRecordExceptionTests : MoqTest .Setup(f => f.CreateLogger("Speckle.Sdk.Serialisation.V2.PriorityScheduler")) .Returns(Create>().Object); var objectSaverMock = Create(); - objectSaverMock.Setup(x => x.Dispose()); var baseChildFinderMock = Create(); var baseSerializerMock = Create(); using var cts = new CancellationTokenSource(); From 424609fad08e2f401196c188d2e85c56486d8c99 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 10 Jun 2025 13:18:34 +0100 Subject: [PATCH 6/6] fix tests --- .../Serialisation/V2/MemoryJsonCacheManager.cs | 2 +- .../DataObjectTests.cs | 2 +- .../Speckle.Sdk.Serialization.Tests/DetachedTests.cs | 12 ++++++------ .../Framework/ExceptionSendCacheManager.cs | 4 +--- .../Framework/DummySqLiteSendManager.cs | 5 ++--- 5 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/Speckle.Sdk/Serialisation/V2/MemoryJsonCacheManager.cs b/src/Speckle.Sdk/Serialisation/V2/MemoryJsonCacheManager.cs index 447c3ce9..21395e5f 100644 --- a/src/Speckle.Sdk/Serialisation/V2/MemoryJsonCacheManager.cs +++ b/src/Speckle.Sdk/Serialisation/V2/MemoryJsonCacheManager.cs @@ -8,7 +8,7 @@ public class MemoryJsonCacheManager(ConcurrentDictionary jsonCache) : #pragma warning restore CA1063 { #pragma warning disable CA1065 - public string Path => throw new NotImplementedException(); + public string Path => "MemoryJsonCacheManager"; #pragma warning restore CA1065 public IReadOnlyCollection<(string Id, string Json)> GetAllObjects() => diff --git a/tests/Speckle.Sdk.Serialization.Tests/DataObjectTests.cs b/tests/Speckle.Sdk.Serialization.Tests/DataObjectTests.cs index da6fdef8..90435f58 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/DataObjectTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/DataObjectTests.cs @@ -41,7 +41,7 @@ public class DataObjectTests new DummyServerObjectManager(), null, default, - new SerializeProcessOptions(true, true, false, true) + new SerializeProcessOptions(false, false, false, true) ); await serializeProcess.Serialize(x); await VerifyJson(json.Single().Value.Value).UseParameters(type); diff --git a/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs b/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs index 6df010aa..62568110 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs @@ -41,7 +41,7 @@ public class DetachedTests objects, null, default, - new SerializeProcessOptions(false, false, true, true) + new SerializeProcessOptions(false, false, false, true) ); await serializeProcess.Serialize(@base); @@ -123,7 +123,7 @@ public class DetachedTests objects, null, default, - new SerializeProcessOptions(false, false, true, true) { MaxParallelism = 1, MaxHttpSendBatchSize = 1 } + new SerializeProcessOptions(false, false, false, true) { MaxParallelism = 1, MaxHttpSendBatchSize = 1 } ); var results = await serializeProcess.Serialize(@base); @@ -150,7 +150,7 @@ public class DetachedTests objects, null, default, - new SerializeProcessOptions(false, false, true, true) { MaxParallelism = 1, MaxHttpSendBatchSize = 1 } + new SerializeProcessOptions(false, false, false, true) { MaxParallelism = 1, MaxHttpSendBatchSize = 1 } ); var results = await serializeProcess.Serialize(@base); @@ -172,7 +172,7 @@ public class DetachedTests objects, null, default, - new SerializeProcessOptions(false, false, true, true) { MaxParallelism = 1, MaxHttpSendBatchSize = 1 } + new SerializeProcessOptions(false, false, false, true) { MaxParallelism = 1, MaxHttpSendBatchSize = 1 } ); var results = await serializeProcess.Serialize(@base); @@ -239,7 +239,7 @@ public class DetachedTests objects, null, default, - new SerializeProcessOptions(false, false, true, true) + new SerializeProcessOptions(false, false, false, true) ); var results = await serializeProcess.Serialize(@base); @@ -272,7 +272,7 @@ public class DetachedTests objects, null, default, - new SerializeProcessOptions(false, false, true, true) + new SerializeProcessOptions(false, false, false, true) ); var results = await serializeProcess.Serialize(@base); await VerifyJsonDictionary(objects); diff --git a/tests/Speckle.Sdk.Serialization.Tests/Framework/ExceptionSendCacheManager.cs b/tests/Speckle.Sdk.Serialization.Tests/Framework/ExceptionSendCacheManager.cs index 22e5372e..0f3df346 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/Framework/ExceptionSendCacheManager.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/Framework/ExceptionSendCacheManager.cs @@ -4,9 +4,7 @@ namespace Speckle.Sdk.Serialization.Tests.Framework; public class ExceptionSendCacheManager(bool? hasObject = null, int? exceptionsAfter = null) : ISqLiteJsonCacheManager { -#pragma warning disable CA1065 - public string Path => throw new NotImplementedException(); -#pragma warning restore CA1065 + public string Path => "ExceptionSendCacheManager"; private readonly object _lock = new(); private int _count; diff --git a/tests/Speckle.Sdk.Testing/Framework/DummySqLiteSendManager.cs b/tests/Speckle.Sdk.Testing/Framework/DummySqLiteSendManager.cs index 63983aa6..97e3f0f5 100644 --- a/tests/Speckle.Sdk.Testing/Framework/DummySqLiteSendManager.cs +++ b/tests/Speckle.Sdk.Testing/Framework/DummySqLiteSendManager.cs @@ -4,9 +4,8 @@ namespace Speckle.Sdk.Testing.Framework; public class DummySqLiteSendManager : ISqLiteJsonCacheManager { -#pragma warning disable CA1065 - public string Path => throw new NotImplementedException(); -#pragma warning restore CA1065 + public string Path => "DummySqLiteSendManager"; + public string? GetObject(string id) => throw new NotImplementedException(); public void SaveObject(string id, string json) => throw new NotImplementedException();