From 630bb38b8bfa6ae3b7919cf1e9f341aea56c9a51 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Mon, 7 Apr 2025 13:43:22 +0100 Subject: [PATCH 1/3] fix: Update HostAppVersion.cs (#273) Adding v2026 for next autodesk releases support. Co-authored-by: Jonathon Broughton <760691+jsdbroughton@users.noreply.github.com> --- src/Speckle.Sdk/Host/HostAppVersion.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Speckle.Sdk/Host/HostAppVersion.cs b/src/Speckle.Sdk/Host/HostAppVersion.cs index 2dc6c540..b18b1a9f 100644 --- a/src/Speckle.Sdk/Host/HostAppVersion.cs +++ b/src/Speckle.Sdk/Host/HostAppVersion.cs @@ -13,6 +13,7 @@ public enum HostAppVersion v2023, v2024, v2025, + v2026, v21, v22, v25, From f163b2822ef7fc2c2930749e66f640c64fff5f50 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 8 Apr 2025 10:21:47 +0100 Subject: [PATCH 2/3] (feat) add memory serialize and make relevant tests use it (#252) * First pass of ObjectSaver and better in-memory usage * fix some tests * add commit to match deserialize process * correct more tests * format * make a deserialize factory * fix tests? and format * use distinct * Fix mismerge * Fix serialization issues with tests * fix merges * follow copilot suggestions * remove disables --- src/Speckle.Sdk.Dependencies/Collections.cs | 19 +++ .../Serialization/ChannelSaver.cs | 18 +-- .../Api/Operations/Operations.Receive.cs | 2 +- src/Speckle.Sdk/Api/Operations/Operations.cs | 3 +- .../V2/DeserializeProcessFactory.cs | 56 ++++++++ .../V2/DummySendServerObjectManager.cs | 68 ---------- .../V2/MemoryJsonCacheManager.cs | 37 +++++ .../V2/MemoryServerObjectManager.cs | 48 +++++++ .../Serialisation/V2/Send/ObjectSaver.cs | 126 ++++++++++++++++++ .../Serialisation/V2/Send/SerializeProcess.cs | 93 ++----------- .../V2/SerializeProcessFactory.cs | 75 ++++++----- .../Program.cs | 19 +-- .../CancellationSqLiteJsonCacheManager.cs | 9 +- .../CancellationTests.cs | 50 +++---- .../DetachedTests.cs | 63 +++++---- .../ExceptionTests.cs | 52 ++++---- .../ExplicitInterfaceTests.cs | 28 ++-- .../Framework/TestFileManager.cs | 52 ++++---- .../SerializationTests.cs | 51 +++---- .../Speckle.Sdk.Serialization.Tests.csproj | 1 + .../packages.lock.json | 9 ++ 21 files changed, 510 insertions(+), 369 deletions(-) create mode 100644 src/Speckle.Sdk/Serialisation/V2/DeserializeProcessFactory.cs delete mode 100644 src/Speckle.Sdk/Serialisation/V2/DummySendServerObjectManager.cs create mode 100644 src/Speckle.Sdk/Serialisation/V2/MemoryJsonCacheManager.cs create mode 100644 src/Speckle.Sdk/Serialisation/V2/MemoryServerObjectManager.cs create mode 100644 src/Speckle.Sdk/Serialisation/V2/Send/ObjectSaver.cs diff --git a/src/Speckle.Sdk.Dependencies/Collections.cs b/src/Speckle.Sdk.Dependencies/Collections.cs index aa622c83..b4c910da 100644 --- a/src/Speckle.Sdk.Dependencies/Collections.cs +++ b/src/Speckle.Sdk.Dependencies/Collections.cs @@ -22,4 +22,23 @@ public static class Collections public static class EnumerableExtensions { public static IEnumerable RangeFrom(int from, int to) => Enumerable.Range(from, to - from + 1); + +#if NETSTANDARD2_0 + public static IEnumerable DistinctBy( + this IEnumerable source, + Func keySelector + ) + { + var keys = new HashSet(); + foreach (var element in source) + { + if (keys.Contains(keySelector(element))) + { + continue; + } + keys.Add(keySelector(element)); + yield return element; + } + } +#endif } diff --git a/src/Speckle.Sdk.Dependencies/Serialization/ChannelSaver.cs b/src/Speckle.Sdk.Dependencies/Serialization/ChannelSaver.cs index a43aa37d..b30f4608 100644 --- a/src/Speckle.Sdk.Dependencies/Serialization/ChannelSaver.cs +++ b/src/Speckle.Sdk.Dependencies/Serialization/ChannelSaver.cs @@ -77,7 +77,7 @@ public abstract class ChannelSaver { try { - await SendToServer((Batch)batch).ConfigureAwait(false); + await SendToServerInternal((Batch)batch).ConfigureAwait(false); return batch; } #pragma warning disable CA1031 @@ -89,20 +89,6 @@ public abstract class ChannelSaver } } - public async Task SendToServer(Batch batch) - { - try - { - await SendToServerInternal(batch).ConfigureAwait(false); - } -#pragma warning disable CA1031 - catch (Exception ex) -#pragma warning restore CA1031 - { - RecordException(ex); - } - } - protected abstract Task SendToServerInternal(Batch batch); public abstract void SaveToCache(List item); @@ -117,7 +103,7 @@ public abstract class ChannelSaver } } - protected Exception? Exception { get; set; } + public Exception? Exception { get; set; } private void RecordException(Exception ex) { diff --git a/src/Speckle.Sdk/Api/Operations/Operations.Receive.cs b/src/Speckle.Sdk/Api/Operations/Operations.Receive.cs index 35aebb4a..5dcd2156 100644 --- a/src/Speckle.Sdk/Api/Operations/Operations.Receive.cs +++ b/src/Speckle.Sdk/Api/Operations/Operations.Receive.cs @@ -29,7 +29,7 @@ public partial class Operations metricsFactory.CreateCounter("Receive").Add(1); receiveActivity?.SetTag("objectId", objectId); - var process = serializeProcessFactory.CreateDeserializeProcess( + var process = deserializeProcessFactory.CreateDeserializeProcess( url, streamId, authorizationToken, diff --git a/src/Speckle.Sdk/Api/Operations/Operations.cs b/src/Speckle.Sdk/Api/Operations/Operations.cs index bb0664f8..cc5aea13 100644 --- a/src/Speckle.Sdk/Api/Operations/Operations.cs +++ b/src/Speckle.Sdk/Api/Operations/Operations.cs @@ -15,5 +15,6 @@ public partial class Operations( ILogger logger, ISdkActivityFactory activityFactory, ISdkMetricsFactory metricsFactory, - ISerializeProcessFactory serializeProcessFactory + ISerializeProcessFactory serializeProcessFactory, + IDeserializeProcessFactory deserializeProcessFactory ) : IOperations; diff --git a/src/Speckle.Sdk/Serialisation/V2/DeserializeProcessFactory.cs b/src/Speckle.Sdk/Serialisation/V2/DeserializeProcessFactory.cs new file mode 100644 index 00000000..27a6c651 --- /dev/null +++ b/src/Speckle.Sdk/Serialisation/V2/DeserializeProcessFactory.cs @@ -0,0 +1,56 @@ +using System.Collections.Concurrent; +using Microsoft.Extensions.Logging; +using Speckle.InterfaceGenerator; +using Speckle.Sdk.Serialisation.V2.Receive; +using Speckle.Sdk.SQLite; +using Speckle.Sdk.Transports; + +namespace Speckle.Sdk.Serialisation.V2; + +[GenerateAutoInterface] +public class DeserializeProcessFactory( + IBaseDeserializer baseDeserializer, + ISqLiteJsonCacheManagerFactory sqLiteJsonCacheManagerFactory, + IServerObjectManagerFactory serverObjectManagerFactory, + ILoggerFactory loggerFactory +) : IDeserializeProcessFactory +{ + public IDeserializeProcess CreateDeserializeProcess( + Uri url, + string streamId, + string? authorizationToken, + IProgress? progress, + CancellationToken cancellationToken, + DeserializeProcessOptions? options = null + ) + { + var sqLiteJsonCacheManager = sqLiteJsonCacheManagerFactory.CreateFromStream(streamId); + var serverObjectManager = serverObjectManagerFactory.Create(url, streamId, authorizationToken); + return new DeserializeProcess( + sqLiteJsonCacheManager, + serverObjectManager, + progress, + baseDeserializer, + loggerFactory, + cancellationToken, + options + ); + } + + public IDeserializeProcess CreateDeserializeProcess( + ConcurrentDictionary jsonCache, + ConcurrentDictionary objects, + IProgress? progress, + CancellationToken cancellationToken, + DeserializeProcessOptions? options = null + ) => + new DeserializeProcess( + new MemoryJsonCacheManager(jsonCache), + new MemoryServerObjectManager(objects), + progress, + baseDeserializer, + loggerFactory, + cancellationToken, + options + ); +} diff --git a/src/Speckle.Sdk/Serialisation/V2/DummySendServerObjectManager.cs b/src/Speckle.Sdk/Serialisation/V2/DummySendServerObjectManager.cs deleted file mode 100644 index 9d1c096a..00000000 --- a/src/Speckle.Sdk/Serialisation/V2/DummySendServerObjectManager.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System.Text; -using Speckle.Sdk.Serialisation.V2.Send; -using Speckle.Sdk.SQLite; -using Speckle.Sdk.Transports; - -namespace Speckle.Sdk.Serialisation.V2; - -#pragma warning disable CA1063 -public class DummySqLiteJsonCacheManager : ISqLiteJsonCacheManager -#pragma warning restore CA1063 -{ -#pragma warning disable CA1816 -#pragma warning disable CA1063 - public void Dispose() { } -#pragma warning restore CA1063 -#pragma warning restore CA1816 - - public IReadOnlyCollection<(string, string)> GetAllObjects() => throw new NotImplementedException(); - - public void DeleteObject(string id) => throw new NotImplementedException(); - - public string? GetObject(string id) => null; - - public void SaveObject(string id, string json) => throw new NotImplementedException(); - - public void UpdateObject(string id, string json) => throw new NotImplementedException(); - - public virtual void SaveObjects(IEnumerable<(string id, string json)> items) => throw new NotImplementedException(); - - public bool HasObject(string objectId) => false; -} - -public class DummySendServerObjectManager : IServerObjectManager -{ - public IAsyncEnumerable<(string, string)> DownloadObjects( - IReadOnlyCollection objectIds, - IProgress? progress, - CancellationToken cancellationToken - ) => throw new NotImplementedException(); - - public Task DownloadSingleObject( - string objectId, - IProgress? progress, - CancellationToken cancellationToken - ) => throw new NotImplementedException(); - - public Task> HasObjects( - IReadOnlyCollection objectIds, - CancellationToken cancellationToken - ) => throw new NotImplementedException(); - - public Task UploadObjects( - IReadOnlyList objects, - bool compressPayloads, - IProgress? progress, - CancellationToken cancellationToken - ) - { - long totalBytes = 0; - foreach (var item in objects) - { - totalBytes += Encoding.Default.GetByteCount(item.Json.Value); - } - - progress?.Report(new(ProgressEvent.UploadBytes, totalBytes, totalBytes)); - return Task.CompletedTask; - } -} diff --git a/src/Speckle.Sdk/Serialisation/V2/MemoryJsonCacheManager.cs b/src/Speckle.Sdk/Serialisation/V2/MemoryJsonCacheManager.cs new file mode 100644 index 00000000..26e142be --- /dev/null +++ b/src/Speckle.Sdk/Serialisation/V2/MemoryJsonCacheManager.cs @@ -0,0 +1,37 @@ +using System.Collections.Concurrent; +using Speckle.Sdk.SQLite; + +namespace Speckle.Sdk.Serialisation.V2; + +#pragma warning disable CA1063 +public class MemoryJsonCacheManager(ConcurrentDictionary jsonCache) : ISqLiteJsonCacheManager +#pragma warning restore CA1063 +{ + public IReadOnlyCollection<(string Id, string Json)> GetAllObjects() => + jsonCache.Select(x => (x.Key.Value, x.Value.Value)).ToList(); + + public void DeleteObject(string id) => jsonCache.TryRemove(new Id(id), out _); + + public string? GetObject(string id) => jsonCache.TryGetValue(new Id(id), out var json) ? json.Value : null; + + public void SaveObject(string id, string json) => jsonCache.TryAdd(new Id(id), new Json(json)); + + public void UpdateObject(string id, string json) => jsonCache[new Id(id)] = new Json(json); + + public virtual void SaveObjects(IEnumerable<(string id, string json)> items) + { + foreach (var (id, json) in items) + { + SaveObject(id, json); + } + } + + public bool HasObject(string objectId) => jsonCache.ContainsKey(new Id(objectId)); + +#pragma warning disable CA1063 +#pragma warning disable CA1816 + public void Dispose() +#pragma warning restore CA1816 +#pragma warning restore CA1063 + { } +} diff --git a/src/Speckle.Sdk/Serialisation/V2/MemoryServerObjectManager.cs b/src/Speckle.Sdk/Serialisation/V2/MemoryServerObjectManager.cs new file mode 100644 index 00000000..f4dda14a --- /dev/null +++ b/src/Speckle.Sdk/Serialisation/V2/MemoryServerObjectManager.cs @@ -0,0 +1,48 @@ +using System.Collections.Concurrent; +using System.Runtime.CompilerServices; +using Speckle.Sdk.Serialisation.V2.Send; +using Speckle.Sdk.Transports; + +namespace Speckle.Sdk.Serialisation.V2; + +public class MemoryServerObjectManager(ConcurrentDictionary objects) : IServerObjectManager +{ + public virtual async IAsyncEnumerable<(string, string)> DownloadObjects( + IReadOnlyCollection objectIds, + IProgress? progress, + [EnumeratorCancellation] CancellationToken cancellationToken + ) + { + foreach (var item in objects.Where(x => objectIds.Contains(x.Key))) + { + cancellationToken.ThrowIfCancellationRequested(); + yield return (item.Key, item.Value); + } + await Task.CompletedTask.ConfigureAwait(false); + } + + public virtual Task DownloadSingleObject( + string objectId, + IProgress? progress, + CancellationToken cancellationToken + ) => Task.FromResult(objects.TryGetValue(objectId, out var json) ? json : null); + + public virtual Task> HasObjects( + IReadOnlyCollection objectIds, + CancellationToken cancellationToken + ) => Task.FromResult(objectIds.ToDictionary(x => x, objects.ContainsKey)); + + public virtual Task UploadObjects( + IReadOnlyList objectToUpload, + bool compressPayloads, + IProgress? progress, + CancellationToken cancellationToken + ) + { + foreach (BaseItem baseItem in objectToUpload) + { + objects.TryAdd(baseItem.Id.Value, baseItem.Json.Value); + } + return Task.CompletedTask; + } +} diff --git a/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSaver.cs b/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSaver.cs new file mode 100644 index 00000000..01c47226 --- /dev/null +++ b/src/Speckle.Sdk/Serialisation/V2/Send/ObjectSaver.cs @@ -0,0 +1,126 @@ +using Microsoft.Extensions.Logging; +using Speckle.Sdk.Dependencies; +using Speckle.Sdk.Dependencies.Serialization; +using Speckle.Sdk.SQLite; +using Speckle.Sdk.Transports; + +namespace Speckle.Sdk.Serialisation.V2.Send; + +public interface IObjectSaver : IDisposable +{ + Exception? Exception { get; set; } + Task Start(CancellationToken cancellationToken); + void DoneTraversing(); + Task DoneSaving(); + void SaveItem(BaseItem item, CancellationToken cancellationToken); +} + +public sealed class ObjectSaver( + IProgress? progress, + ISqLiteJsonCacheManager sqLiteJsonCacheManager, + IServerObjectManager serverObjectManager, + ILogger logger, + CancellationToken cancellationToken, +#pragma warning disable CS9107 +#pragma warning disable CA2254 + SerializeProcessOptions? options = null +) : ChannelSaver, IObjectSaver +#pragma warning restore CA2254 +#pragma warning restore CS9107 +{ + private readonly CancellationTokenSource _cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource( + cancellationToken + ); + + private readonly SerializeProcessOptions _options = options ?? new(); + + private long _uploaded; + private long _cached; + + private long _objectsSerialized; + + protected override async Task SendToServerInternal(Batch batch) + { + if (_cancellationTokenSource.IsCancellationRequested) + { + return; + } + try + { + if (!_options.SkipServer && batch.Items.Count != 0) + { + var objectBatch = batch.Items.Distinct().ToList(); + var hasObjects = await serverObjectManager + .HasObjects(objectBatch.Select(x => x.Id.Value).Freeze(), _cancellationTokenSource.Token) + .ConfigureAwait(false); + objectBatch = batch.Items.Where(x => !hasObjects[x.Id.Value]).ToList(); + if (objectBatch.Count != 0) + { + await serverObjectManager + .UploadObjects(objectBatch, true, progress, _cancellationTokenSource.Token) + .ConfigureAwait(false); + Interlocked.Add(ref _uploaded, batch.Items.Count); + } + + progress?.Report(new(ProgressEvent.UploadedObjects, _uploaded, null)); + } + } + catch (OperationCanceledException) + { + _cancellationTokenSource.Cancel(); + } +#pragma warning disable CA1031 + catch (Exception e) +#pragma warning restore CA1031 + { + RecordException(e); + } + } + + public void SaveItem(BaseItem item, CancellationToken cancellationToken) + { + Interlocked.Increment(ref _objectsSerialized); + Save(item, cancellationToken); + } + + public override void SaveToCache(List batch) + { + if (_cancellationTokenSource.IsCancellationRequested) + { + return; + } + try + { + if (!_options.SkipCacheWrite && batch.Count != 0) + { + sqLiteJsonCacheManager.SaveObjects(batch.Select(x => (x.Id.Value, x.Json.Value))); + Interlocked.Add(ref _cached, batch.Count); + progress?.Report(new(ProgressEvent.CachedToLocal, _cached, _objectsSerialized)); + } + } + catch (OperationCanceledException) + { + _cancellationTokenSource.Cancel(); + } +#pragma warning disable CA1031 + catch (Exception e) +#pragma warning restore CA1031 + { + RecordException(e); + } + } + + private void RecordException(Exception e) + { + //order here matters + logger.LogError(e, "Error in SDK"); + Exception = e; + _cancellationTokenSource.Cancel(); + } + + public void Dispose() + { + _cancellationTokenSource.Dispose(); + sqLiteJsonCacheManager.Dispose(); + } +} diff --git a/src/Speckle.Sdk/Serialisation/V2/Send/SerializeProcess.cs b/src/Speckle.Sdk/Serialisation/V2/Send/SerializeProcess.cs index c8a84fb8..df27e577 100644 --- a/src/Speckle.Sdk/Serialisation/V2/Send/SerializeProcess.cs +++ b/src/Speckle.Sdk/Serialisation/V2/Send/SerializeProcess.cs @@ -4,9 +4,7 @@ using Microsoft.Extensions.Logging; using Speckle.InterfaceGenerator; using Speckle.Sdk.Common; using Speckle.Sdk.Dependencies; -using Speckle.Sdk.Dependencies.Serialization; using Speckle.Sdk.Models; -using Speckle.Sdk.SQLite; using Speckle.Sdk.Transports; namespace Speckle.Sdk.Serialisation.V2.Send; @@ -28,20 +26,20 @@ public partial interface ISerializeProcess : IAsyncDisposable; [GenerateAutoInterface] public sealed class SerializeProcess( IProgress? progress, - ISqLiteJsonCacheManager sqLiteJsonCacheManager, - IServerObjectManager serverObjectManager, + IObjectSaver objectSaver, IBaseChildFinder baseChildFinder, IBaseSerializer baseSerializer, ILoggerFactory loggerFactory, CancellationToken cancellationToken, SerializeProcessOptions? options = null -) : ChannelSaver, ISerializeProcess +) : ISerializeProcess { private static readonly Dictionary EMPTY_CLOSURES = new(); private readonly CancellationTokenSource _processSource = CancellationTokenSource.CreateLinkedTokenSource( cancellationToken ); + private readonly ILogger _logger = loggerFactory.CreateLogger(); //async dispose [SuppressMessage("Usage", "CA2213:Disposable fields should be disposed")] @@ -59,7 +57,6 @@ public sealed class SerializeProcess( Environment.ProcessorCount * 2 ); private readonly SerializeProcessOptions _options = options ?? new(); - private readonly ILogger _logger = loggerFactory.CreateLogger(); private readonly Pool> _currentClosurePool = Pools.CreateDictionaryPool(); private readonly Pool> _childClosurePool = Pools.CreateConcurrentDictionaryPool< @@ -72,25 +69,22 @@ public sealed class SerializeProcess( private long _objectsSerialized; - private long _uploaded; - private long _cached; - [AutoInterfaceIgnore] public async ValueTask DisposeAsync() { await WaitForSchedulerCompletion().ConfigureAwait(false); await _highest.DisposeAsync().ConfigureAwait(false); await _belowNormal.DisposeAsync().ConfigureAwait(false); - sqLiteJsonCacheManager.Dispose(); + objectSaver.Dispose(); _processSource.Dispose(); } private void ThrowIfFailed() { //order here matters...null with cancellation means a user did it, otherwise it's a real Exception - if (Exception is not null) + if (objectSaver.Exception is not null) { - throw new SpeckleException("Error while sending", Exception); + throw new SpeckleException("Error while sending", objectSaver.Exception); } _processSource.Token.ThrowIfCancellationRequested(); } @@ -105,7 +99,7 @@ public sealed class SerializeProcess( { try { - var channelTask = Start(_processSource.Token); + var channelTask = objectSaver.Start(_processSource.Token); var findTotalObjectsTask = Task.CompletedTask; if (!_options.SkipFindTotalObjects) { @@ -120,10 +114,10 @@ public sealed class SerializeProcess( await Traverse(root, _processSource.Token).ConfigureAwait(false); ThrowIfFailed(); - DoneTraversing(); + objectSaver.DoneTraversing(); await Task.WhenAll(findTotalObjectsTask, channelTask).ConfigureAwait(false); ThrowIfFailed(); - await DoneSaving().ConfigureAwait(false); + await objectSaver.DoneSaving().ConfigureAwait(false); ThrowIfFailed(); await WaitForSchedulerCompletion().ConfigureAwait(false); ThrowIfFailed(); @@ -254,7 +248,7 @@ public sealed class SerializeProcess( } Interlocked.Increment(ref _objectsSerialized); - Save(item, childCancellationTokenSource.Token); + objectSaver.SaveItem(item, childCancellationTokenSource.Token); } if (!currentClosures.ContainsKey(item.Id)) @@ -283,76 +277,11 @@ public sealed class SerializeProcess( } } - protected override async Task SendToServerInternal(Batch batch) - { - if (_processSource.IsCancellationRequested) - { - return; - } - try - { - if (!_options.SkipServer && batch.Items.Count != 0) - { - var objectBatch = batch.Items.Distinct().ToList(); - var hasObjects = await serverObjectManager - .HasObjects(objectBatch.Select(x => x.Id.Value).Freeze(), _processSource.Token) - .ConfigureAwait(false); - objectBatch = batch.Items.Where(x => !hasObjects[x.Id.Value]).ToList(); - if (objectBatch.Count != 0) - { - await serverObjectManager - .UploadObjects(objectBatch, true, progress, _processSource.Token) - .ConfigureAwait(false); - Interlocked.Exchange(ref _uploaded, _uploaded + batch.Items.Count); - } - - progress?.Report(new(ProgressEvent.UploadedObjects, _uploaded, null)); - } - } - catch (OperationCanceledException) - { - _processSource.Cancel(); - } -#pragma warning disable CA1031 - catch (Exception e) -#pragma warning restore CA1031 - { - RecordException(e); - } - } - - public override void SaveToCache(List batch) - { - if (_processSource.IsCancellationRequested) - { - return; - } - try - { - if (!_options.SkipCacheWrite && batch.Count != 0) - { - sqLiteJsonCacheManager.SaveObjects(batch.Select(x => (x.Id.Value, x.Json.Value))); - Interlocked.Exchange(ref _cached, _cached + batch.Count); - progress?.Report(new(ProgressEvent.CachedToLocal, _cached, _objectsSerialized)); - } - } - catch (OperationCanceledException) - { - _processSource.Cancel(); - } -#pragma warning disable CA1031 - catch (Exception e) -#pragma warning restore CA1031 - { - RecordException(e); - } - } - private void RecordException(Exception e) { //order here matters _logger.LogError(e, "Error in SDK"); - Exception = e; + objectSaver.Exception = e; _processSource.Cancel(); } } diff --git a/src/Speckle.Sdk/Serialisation/V2/SerializeProcessFactory.cs b/src/Speckle.Sdk/Serialisation/V2/SerializeProcessFactory.cs index 863d7026..550cfa4b 100644 --- a/src/Speckle.Sdk/Serialisation/V2/SerializeProcessFactory.cs +++ b/src/Speckle.Sdk/Serialisation/V2/SerializeProcessFactory.cs @@ -1,35 +1,16 @@ +using System.Collections.Concurrent; using Microsoft.Extensions.Logging; -using Speckle.Sdk.Serialisation.V2.Receive; +using Speckle.InterfaceGenerator; using Speckle.Sdk.Serialisation.V2.Send; using Speckle.Sdk.SQLite; using Speckle.Sdk.Transports; namespace Speckle.Sdk.Serialisation.V2; -public interface ISerializeProcessFactory -{ - ISerializeProcess CreateSerializeProcess( - Uri url, - string streamId, - string? authorizationToken, - IProgress? progress, - CancellationToken cancellationToken, - SerializeProcessOptions? options = null - ); - IDeserializeProcess CreateDeserializeProcess( - Uri url, - string streamId, - string? authorizationToken, - IProgress? progress, - CancellationToken cancellationToken, - DeserializeProcessOptions? options = null - ); -} - +[GenerateAutoInterface] public class SerializeProcessFactory( IBaseChildFinder baseChildFinder, IObjectSerializerFactory objectSerializerFactory, - IBaseDeserializer baseDeserializer, ISqLiteJsonCacheManagerFactory sqLiteJsonCacheManagerFactory, IServerObjectManagerFactory serverObjectManagerFactory, ILoggerFactory loggerFactory @@ -46,34 +27,54 @@ public class SerializeProcessFactory( { var sqLiteJsonCacheManager = sqLiteJsonCacheManagerFactory.CreateFromStream(streamId); var serverObjectManager = serverObjectManagerFactory.Create(url, streamId, authorizationToken); - return new SerializeProcess( + return CreateSerializeProcess(sqLiteJsonCacheManager, serverObjectManager, progress, cancellationToken, options); + } + + public ISerializeProcess CreateSerializeProcess( + ISqLiteJsonCacheManager sqLiteJsonCacheManager, + IServerObjectManager serverObjectManager, + IProgress? progress, + CancellationToken cancellationToken, + SerializeProcessOptions? options = null + ) => + new SerializeProcess( progress, - sqLiteJsonCacheManager, - serverObjectManager, + new ObjectSaver( + progress, + sqLiteJsonCacheManager, + serverObjectManager, + loggerFactory.CreateLogger(), + cancellationToken + ), baseChildFinder, new BaseSerializer(sqLiteJsonCacheManager, objectSerializerFactory), loggerFactory, cancellationToken, options ); - } - public IDeserializeProcess CreateDeserializeProcess( - Uri url, - string streamId, - string? authorizationToken, + public ISerializeProcess CreateSerializeProcess( + ConcurrentDictionary jsonCache, + ConcurrentDictionary objects, IProgress? progress, CancellationToken cancellationToken, - DeserializeProcessOptions? options = null + SerializeProcessOptions? options = null ) { - var sqLiteJsonCacheManager = sqLiteJsonCacheManagerFactory.CreateFromStream(streamId); - var serverObjectManager = serverObjectManagerFactory.Create(url, streamId, authorizationToken); - return new DeserializeProcess( - sqLiteJsonCacheManager, - serverObjectManager, +#pragma warning disable CA2000 + var memoryJsonCacheManager = new MemoryJsonCacheManager(jsonCache); +#pragma warning restore CA2000 + return new SerializeProcess( progress, - baseDeserializer, + 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.Testing/Program.cs b/tests/Speckle.Sdk.Serialization.Testing/Program.cs index 51b285eb..ca7a9d92 100644 --- a/tests/Speckle.Sdk.Serialization.Testing/Program.cs +++ b/tests/Speckle.Sdk.Serialization.Testing/Program.cs @@ -1,16 +1,13 @@ #pragma warning disable CA1506 using System.Reflection; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging.Abstractions; using Speckle.Sdk; using Speckle.Sdk.Credentials; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Serialisation.V2; -using Speckle.Sdk.Serialisation.V2.Receive; using Speckle.Sdk.Serialisation.V2.Send; using Speckle.Sdk.Serialization.Testing; -using Speckle.Sdk.SQLite; const bool skipCacheReceive = false; const bool skipCacheSendCheck = true; @@ -41,21 +38,15 @@ Console.WriteLine("Attach"); var token = serviceProvider.GetRequiredService().GetDefaultAccount()?.token; var progress = new Progress(true); -var factory = new SerializeProcessFactory( - new BaseChildFinder(new BasePropertyGatherer()), - new ObjectSerializerFactory(new BasePropertyGatherer()), - new BaseDeserializer(new ObjectDeserializerFactory()), - serviceProvider.GetRequiredService(), - serviceProvider.GetRequiredService(), - new NullLoggerFactory() -); +var factory = serviceProvider.GetRequiredService(); var process = factory.CreateDeserializeProcess(new Uri(url), streamId, token, progress, default, new(skipCacheReceive)); var @base = await process.Deserialize(rootId).ConfigureAwait(false); Console.WriteLine("Deserialized"); Console.ReadLine(); Console.WriteLine("Executing"); -var process2 = factory.CreateSerializeProcess( +var serializeProcessFactory = serviceProvider.GetRequiredService(); +var serializeProcess = serializeProcessFactory.CreateSerializeProcess( new Uri(url), streamId, token, @@ -63,8 +54,8 @@ var process2 = factory.CreateSerializeProcess( default, new SerializeProcessOptions(skipCacheSendCheck, skipCacheSendSave, true, true) ); -await process2.Serialize(@base).ConfigureAwait(false); +await serializeProcess.Serialize(@base).ConfigureAwait(false); Console.WriteLine("Detach"); Console.ReadLine(); -await process2.DisposeAsync().ConfigureAwait(false); +await serializeProcess.DisposeAsync().ConfigureAwait(false); #pragma warning restore CA1506 diff --git a/tests/Speckle.Sdk.Serialization.Tests/CancellationSqLiteJsonCacheManager.cs b/tests/Speckle.Sdk.Serialization.Tests/CancellationSqLiteJsonCacheManager.cs index c4d8d355..bbe6b8b1 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/CancellationSqLiteJsonCacheManager.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/CancellationSqLiteJsonCacheManager.cs @@ -1,4 +1,6 @@ -using Speckle.Sdk.Serialisation.V2; +using System.Collections.Concurrent; +using Speckle.Sdk.Serialisation; +using Speckle.Sdk.Serialisation.V2; using Speckle.Sdk.Serialisation.V2.Send; using Speckle.Sdk.Testing.Framework; using Speckle.Sdk.Transports; @@ -6,7 +8,7 @@ using Speckle.Sdk.Transports; namespace Speckle.Sdk.Serialization.Tests; public sealed class CancellationSqLiteJsonCacheManager(CancellationTokenSource cancellationTokenSource) - : DummySqLiteJsonCacheManager + : MemoryJsonCacheManager(new ConcurrentDictionary()) { public override void SaveObjects(IEnumerable<(string id, string json)> items) { @@ -24,7 +26,8 @@ public class CancellationSqLiteSendManager(CancellationTokenSource cancellationT } } -public class CancellationServerObjectManager(CancellationTokenSource cancellationTokenSource) : DummyServerObjectManager +public class CancellationServerObjectManager(CancellationTokenSource cancellationTokenSource) + : MemoryServerObjectManager(new ConcurrentDictionary()) { public override Task UploadObjects( IReadOnlyList objects, diff --git a/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.cs b/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.cs index 5e2995a0..fba0327b 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.cs @@ -1,10 +1,12 @@ using System.Collections.Concurrent; using FluentAssertions; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging.Abstractions; using Speckle.Objects.Geometry; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Serialisation; +using Speckle.Sdk.Serialisation.V2; using Speckle.Sdk.Serialisation.V2.Receive; using Speckle.Sdk.Serialisation.V2.Send; using Speckle.Sdk.Serialization.Tests.Framework; @@ -14,10 +16,18 @@ namespace Speckle.Sdk.Serialization.Tests; public class CancellationTests { + private readonly ISerializeProcessFactory _factory; + public CancellationTests() { TypeLoader.Reset(); - TypeLoader.Initialize(typeof(Base).Assembly, typeof(DetachedTests).Assembly, typeof(Polyline).Assembly); + TypeLoader.Initialize(typeof(Base).Assembly, typeof(TestClass).Assembly, typeof(Polyline).Assembly); + + var serviceCollection = new ServiceCollection(); + serviceCollection.AddSpeckleSdk(HostApplications.Navisworks, HostAppVersion.v2023, "Test"); + var serviceProvider = serviceCollection.BuildServiceProvider(); + + _factory = serviceProvider.GetRequiredService(); } [Fact] @@ -26,13 +36,11 @@ public class CancellationTests var testClass = new TestClass() { RegularProperty = "Hello" }; using var cancellationSource = new CancellationTokenSource(); - await using var serializeProcess = new SerializeProcess( + + await using var serializeProcess = _factory.CreateSerializeProcess( + new ConcurrentDictionary(), + new ConcurrentDictionary(), null, - new DummySqLiteSendManager(), - new DummyServerObjectManager(), - new BaseChildFinder(new BasePropertyGatherer()), - new BaseSerializer(new DummySqLiteSendManager(), new ObjectSerializerFactory(new BasePropertyGatherer())), - new NullLoggerFactory(), cancellationSource.Token, new SerializeProcessOptions(true, true, false, true) ); @@ -50,15 +58,13 @@ public class CancellationTests var testClass = new TestClass() { RegularProperty = "Hello" }; using var cancellationSource = new CancellationTokenSource(); - await using var serializeProcess = new SerializeProcess( - null, + + await using var serializeProcess = _factory.CreateSerializeProcess( new DummySqLiteSendManager(), new CancellationServerObjectManager(cancellationSource), - new BaseChildFinder(new BasePropertyGatherer()), - new BaseSerializer(new DummySqLiteSendManager(), new ObjectSerializerFactory(new BasePropertyGatherer())), - new NullLoggerFactory(), + null, cancellationSource.Token, - new SerializeProcessOptions(true, false, false, true) + new SerializeProcessOptions(true, true, false, true) ); var ex = await Assert.ThrowsAsync( async () => await serializeProcess.Serialize(testClass) @@ -73,16 +79,14 @@ public class CancellationTests var testClass = new TestClass() { RegularProperty = "Hello" }; using var cancellationSource = new CancellationTokenSource(); - await using var serializeProcess = new SerializeProcess( + await using var serializeProcess = _factory.CreateSerializeProcess( + new DummySqLiteSendManager(), + new CancellationServerObjectManager(cancellationSource), null, - new CancellationSqLiteSendManager(cancellationSource), - new DummyServerObjectManager(), - new BaseChildFinder(new BasePropertyGatherer()), - new BaseSerializer(new DummySqLiteSendManager(), new ObjectSerializerFactory(new BasePropertyGatherer())), - new NullLoggerFactory(), cancellationSource.Token, - new SerializeProcessOptions(true, false, false, true) + new SerializeProcessOptions(true, true, false, true) ); + var ex = await Assert.ThrowsAsync( async () => await serializeProcess.Serialize(testClass) ); @@ -94,7 +98,7 @@ public class CancellationTests [InlineData("RevitObject.json.gz", "3416d3fe01c9196115514c4a2f41617b", 7818)] public async Task Cancellation_Receive_Cache(string fileName, string rootId, int oldCount) { - var closures = await TestFileManager.GetFileAsClosures(fileName); + var closures = TestFileManager.GetFileAsClosures(fileName); closures.Count.Should().Be(oldCount); using var cancellationSource = new CancellationTokenSource(); @@ -121,7 +125,7 @@ public class CancellationTests [InlineData("RevitObject.json.gz", "3416d3fe01c9196115514c4a2f41617b", 7818)] public async Task Cancellation_Receive_Server(string fileName, string rootId, int oldCount) { - var closures = await TestFileManager.GetFileAsClosures(fileName); + var closures = TestFileManager.GetFileAsClosures(fileName); closures.Count.Should().Be(oldCount); using var cancellationSource = new CancellationTokenSource(); @@ -148,7 +152,7 @@ public class CancellationTests [InlineData("RevitObject.json.gz", "3416d3fe01c9196115514c4a2f41617b", 7818)] public async Task Cancellation_Receive_Deserialize(string fileName, string rootId, int oldCount) { - var closures = await TestFileManager.GetFileAsClosures(fileName); + var closures = TestFileManager.GetFileAsClosures(fileName); closures.Count.Should().Be(oldCount); using var cancellationSource = new CancellationTokenSource(); diff --git a/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs b/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs index add4126d..ce06d3cc 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs @@ -1,7 +1,7 @@ using System.Collections.Concurrent; using System.Text; using FluentAssertions; -using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.DependencyInjection; using Speckle.Newtonsoft.Json.Linq; using Speckle.Objects.Geometry; using Speckle.Sdk.Host; @@ -16,10 +16,18 @@ namespace Speckle.Sdk.Serialization.Tests; public class DetachedTests { + private readonly ISerializeProcessFactory _factory; + public DetachedTests() { TypeLoader.Reset(); TypeLoader.Initialize(typeof(Base).Assembly, typeof(DetachedTests).Assembly, typeof(Polyline).Assembly); + + var serviceCollection = new ServiceCollection(); + serviceCollection.AddSpeckleSdk(HostApplications.Navisworks, HostAppVersion.v2023, "Test"); + var serviceProvider = serviceCollection.BuildServiceProvider(); + + _factory = serviceProvider.GetRequiredService(); } [Fact] @@ -30,19 +38,16 @@ public class DetachedTests @base.detachedProp = new SamplePropBase() { name = "detachedProp" }; @base.attachedProp = new SamplePropBase() { name = "attachedProp" }; - var objects = new Dictionary(); + var objects = new ConcurrentDictionary(); - await using var process2 = new SerializeProcess( + await using var serializeProcess = _factory.CreateSerializeProcess( + new ConcurrentDictionary(), + objects, null, - new DummySendCacheManager(objects), - new DummyServerObjectManager(), - new BaseChildFinder(new BasePropertyGatherer()), - new BaseSerializer(new DummySendCacheManager(objects), new ObjectSerializerFactory(new BasePropertyGatherer())), - new NullLoggerFactory(), default, new SerializeProcessOptions(false, false, true, true) ); - await process2.Serialize(@base); + await serializeProcess.Serialize(@base); await VerifyJsonDictionary(objects); } @@ -115,19 +120,16 @@ public class DetachedTests line = new Polyline() { units = "test", value = [3.0, 4.0] }, }; - var objects = new Dictionary(); + var objects = new ConcurrentDictionary(); - await using var process2 = new SerializeProcess( + await using var serializeProcess = _factory.CreateSerializeProcess( + new ConcurrentDictionary(), + objects, null, - new DummySendCacheManager(objects), - new DummyServerObjectManager(), - new BaseChildFinder(new BasePropertyGatherer()), - new BaseSerializer(new DummySendCacheManager(objects), new ObjectSerializerFactory(new BasePropertyGatherer())), - new NullLoggerFactory(), default, new SerializeProcessOptions(false, false, true, true) ); - var results = await process2.Serialize(@base); + var results = await serializeProcess.Serialize(@base); await VerifyJsonDictionary(objects); } @@ -185,19 +187,17 @@ public class DetachedTests @base.list = new List() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; @base.list2 = new List() { 1, 10 }; - var objects = new Dictionary(); + var objects = new ConcurrentDictionary(); - await using var process2 = new SerializeProcess( + await using var serializeProcess = _factory.CreateSerializeProcess( + new ConcurrentDictionary(), + objects, null, - new DummySendCacheManager(objects), - new DummyServerObjectManager(), - new BaseChildFinder(new BasePropertyGatherer()), - new BaseSerializer(new DummySendCacheManager(objects), new ObjectSerializerFactory(new BasePropertyGatherer())), - new NullLoggerFactory(), default, new SerializeProcessOptions(false, false, true, true) ); - var results = await process2.Serialize(@base); + + var results = await serializeProcess.Serialize(@base); objects.Count.Should().Be(3); var x = JObject.Parse(objects["efeadaca70a85ae6d3acfc93a8b380db"]); @@ -220,19 +220,16 @@ public class DetachedTests @base.list2 = new List() { 1, 10 }; @base.arr = [1, 10]; - var objects = new Dictionary(); + var objects = new ConcurrentDictionary(); - await using var process2 = new SerializeProcess( + await using var serializeProcess = _factory.CreateSerializeProcess( + new ConcurrentDictionary(), + objects, null, - new DummySendCacheManager(objects), - new DummyServerObjectManager(), - new BaseChildFinder(new BasePropertyGatherer()), - new BaseSerializer(new DummySendCacheManager(objects), new ObjectSerializerFactory(new BasePropertyGatherer())), - new NullLoggerFactory(), default, new SerializeProcessOptions(false, false, true, true) ); - var results = await process2.Serialize(@base); + var results = await serializeProcess.Serialize(@base); await VerifyJsonDictionary(objects); } } diff --git a/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.cs b/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.cs index 7a58d3d1..d31b80d1 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.cs @@ -1,9 +1,12 @@ +using System.Collections.Concurrent; using FluentAssertions; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging.Abstractions; using Speckle.Objects.Geometry; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Serialisation; +using Speckle.Sdk.Serialisation.V2; using Speckle.Sdk.Serialisation.V2.Receive; using Speckle.Sdk.Serialisation.V2.Send; using Speckle.Sdk.Serialization.Tests.Framework; @@ -13,10 +16,18 @@ namespace Speckle.Sdk.Serialization.Tests; public class ExceptionTests { + private readonly ISerializeProcessFactory _factory; + public ExceptionTests() { TypeLoader.Reset(); TypeLoader.Initialize(typeof(Base).Assembly, typeof(DetachedTests).Assembly, typeof(Polyline).Assembly); + + var serviceCollection = new ServiceCollection(); + serviceCollection.AddSpeckleSdk(HostApplications.Navisworks, HostAppVersion.v2023, "Test"); + var serviceProvider = serviceCollection.BuildServiceProvider(); + + _factory = serviceProvider.GetRequiredService(); } [Fact] @@ -24,20 +35,18 @@ public class ExceptionTests { var testClass = new TestClass() { RegularProperty = "Hello" }; - var objects = new Dictionary(); - await using var process2 = new SerializeProcess( - null, - new DummySendCacheManager(objects), + var objects = new ConcurrentDictionary(); + + await using var serializeProcess = _factory.CreateSerializeProcess( + new MemoryJsonCacheManager(objects), new ExceptionServerObjectManager(), - new BaseChildFinder(new BasePropertyGatherer()), - new BaseSerializer(new DummySendCacheManager(objects), new ObjectSerializerFactory(new BasePropertyGatherer())), - new NullLoggerFactory(), + null, default, new SerializeProcessOptions(false, false, false, true) ); //4 exceptions are fine because we use 4 threads for saving cache - var ex = await Assert.ThrowsAsync(async () => await process2.Serialize(testClass)); + var ex = await Assert.ThrowsAsync(async () => await serializeProcess.Serialize(testClass)); await Verify(ex); } @@ -46,18 +55,15 @@ public class ExceptionTests { var testClass = new TestClass() { RegularProperty = "Hello" }; - await using var process2 = new SerializeProcess( - null, + await using var serializeProcess = _factory.CreateSerializeProcess( new ExceptionSendCacheManager(), - new DummyServerObjectManager(), - new BaseChildFinder(new BasePropertyGatherer()), - new BaseSerializer(new ExceptionSendCacheManager(), new ObjectSerializerFactory(new BasePropertyGatherer())), - new NullLoggerFactory(), + new MemoryServerObjectManager(new()), + null, default, new SerializeProcessOptions(false, false, false, true) ); - var ex = await Assert.ThrowsAsync(async () => await process2.Serialize(testClass)); + var ex = await Assert.ThrowsAsync(async () => await serializeProcess.Serialize(testClass)); await Verify(ex); } @@ -66,19 +72,15 @@ public class ExceptionTests { var testClass = new TestClass() { RegularProperty = "Hello" }; - var jsonManager = new ExceptionSendCacheManager(exceptionsAfter: 10); - await using var process2 = new SerializeProcess( + await using var serializeProcess = _factory.CreateSerializeProcess( + new ExceptionSendCacheManager(exceptionsAfter: 10), + new MemoryServerObjectManager(new()), null, - jsonManager, - new DummyServerObjectManager(), - new BaseChildFinder(new BasePropertyGatherer()), - new BaseSerializer(jsonManager, new ObjectSerializerFactory(new BasePropertyGatherer())), - new NullLoggerFactory(), default, new SerializeProcessOptions(false, false, false, true) ); - var ex = await Assert.ThrowsAsync(async () => await process2.Serialize(testClass)); + var ex = await Assert.ThrowsAsync(async () => await serializeProcess.Serialize(testClass)); await Verify(ex); } @@ -111,7 +113,7 @@ public class ExceptionTests [InlineData("RevitObject.json.gz", "3416d3fe01c9196115514c4a2f41617b", 7818)] public async Task Test_Exceptions_Receive_Server(string fileName, string rootId, int oldCount) { - var closures = await TestFileManager.GetFileAsClosures(fileName); + var closures = TestFileManager.GetFileAsClosures(fileName); closures.Count.Should().Be(oldCount); await using var process = new DeserializeProcess( @@ -136,7 +138,7 @@ public class ExceptionTests [InlineData("RevitObject.json.gz", "3416d3fe01c9196115514c4a2f41617b", 7818, true)] public async Task Test_Exceptions_Receive_Cache(string fileName, string rootId, int oldCount, bool? hasObject) { - var closures = await TestFileManager.GetFileAsClosures(fileName); + var closures = TestFileManager.GetFileAsClosures(fileName); closures.Count.Should().Be(oldCount); await using var process = new DeserializeProcess( diff --git a/tests/Speckle.Sdk.Serialization.Tests/ExplicitInterfaceTests.cs b/tests/Speckle.Sdk.Serialization.Tests/ExplicitInterfaceTests.cs index 0bd05a14..dc46b582 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/ExplicitInterfaceTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/ExplicitInterfaceTests.cs @@ -1,16 +1,27 @@ -using Microsoft.Extensions.Logging.Abstractions; +using System.Collections.Concurrent; +using Microsoft.Extensions.DependencyInjection; using Speckle.Sdk.Host; using Speckle.Sdk.Models; +using Speckle.Sdk.Serialisation; +using Speckle.Sdk.Serialisation.V2; using Speckle.Sdk.Serialisation.V2.Send; namespace Speckle.Sdk.Serialization.Tests; public class ExplicitInterfaceTests { + private readonly ISerializeProcessFactory _factory; + public ExplicitInterfaceTests() { TypeLoader.Reset(); TypeLoader.Initialize(typeof(Base).Assembly, typeof(TestClass).Assembly); + + var serviceCollection = new ServiceCollection(); + serviceCollection.AddSpeckleSdk(HostApplications.Navisworks, HostAppVersion.v2023, "Test"); + var serviceProvider = serviceCollection.BuildServiceProvider(); + + _factory = serviceProvider.GetRequiredService(); } [Fact] @@ -18,19 +29,16 @@ public class ExplicitInterfaceTests { var testClass = new TestClass() { RegularProperty = "Hello" }; - var objects = new Dictionary(); - await using var process2 = new SerializeProcess( + var objects = new ConcurrentDictionary(); + await using var serializeProcess = _factory.CreateSerializeProcess( + new ConcurrentDictionary(), + objects, null, - new DummySendCacheManager(objects), - new DummyServerObjectManager(), - new BaseChildFinder(new BasePropertyGatherer()), - new BaseSerializer(new DummySendCacheManager(objects), new ObjectSerializerFactory(new BasePropertyGatherer())), - new NullLoggerFactory(), default, - new SerializeProcessOptions(false, false, true, true) + new SerializeProcessOptions(true, true, false, true) ); - await process2.Serialize(testClass); + await serializeProcess.Serialize(testClass); await VerifyJsonDictionary(objects); } diff --git a/tests/Speckle.Sdk.Serialization.Tests/Framework/TestFileManager.cs b/tests/Speckle.Sdk.Serialization.Tests/Framework/TestFileManager.cs index 34b738e1..a07f05c2 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/Framework/TestFileManager.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/Framework/TestFileManager.cs @@ -1,7 +1,8 @@ -using System.IO.Compression; +using System.Collections.Concurrent; +using System.IO.Compression; using System.Reflection; using Speckle.Newtonsoft.Json.Linq; -using Speckle.Objects.Data; +using Speckle.Objects.Geometry; using Speckle.Sdk.Common; using Speckle.Sdk.Host; using Speckle.Sdk.Models; @@ -10,49 +11,50 @@ namespace Speckle.Sdk.Serialization.Tests.Framework; public static class TestFileManager { - static TestFileManager() - { - TypeLoader.Reset(); - TypeLoader.Initialize(typeof(Base).Assembly, typeof(DataObject).Assembly, _assembly); - } + private static readonly Assembly s_assembly = Assembly.GetExecutingAssembly(); //test + private static readonly Assembly s_speckleAssembly = typeof(Base).Assembly; //speckle.sdk + private static readonly Assembly s_speckleObjectsAssembly = typeof(Polyline).Assembly; //speckle.sdk + private static readonly Dictionary> s_objects = new(); - private static readonly Assembly _assembly = Assembly.GetExecutingAssembly(); - private static readonly Dictionary> _objects = new(); - - public static async Task> GetFileAsClosures(string fileName) + public static IReadOnlyDictionary GetFileAsClosures(string fileName) { - if (!_objects.TryGetValue(fileName, out var closure)) + lock (s_objects) { - var fullName = _assembly.GetManifestResourceNames().Single(x => x.EndsWith(fileName)); - var json = await ReadJson(fullName); - closure = ReadAsObjects(json); - _objects.Add(fileName, closure); + if (!s_objects.TryGetValue(fileName, out var closure)) + { + TypeLoader.Reset(); + TypeLoader.Initialize(s_assembly, s_speckleAssembly, s_speckleObjectsAssembly); + var fullName = s_assembly.GetManifestResourceNames().Single(x => x.EndsWith(fileName)); + var json = ReadJson(fullName); + closure = ReadAsObjects(json); + s_objects.Add(fileName, closure); + } + return closure; } - return closure; } - private static async Task ReadJson(string fullName) + private static string ReadJson(string fullName) { - await using var stream = _assembly.GetManifestResourceStream(fullName).NotNull(); + using var stream = s_assembly.GetManifestResourceStream(fullName).NotNull(); if (fullName.EndsWith(".gz")) { - await using var z = new GZipStream(stream, CompressionMode.Decompress); + using var z = new GZipStream(stream, CompressionMode.Decompress); using var reader2 = new StreamReader(z); - return await reader2.ReadToEndAsync(); + return reader2.ReadToEnd(); } using var reader = new StreamReader(stream); - return await reader.ReadToEndAsync(); + return reader.ReadToEnd(); } - private static Dictionary ReadAsObjects(string json) + private static ConcurrentDictionary ReadAsObjects(string json) { - var jsonObjects = new Dictionary(); + var jsonObjects = new ConcurrentDictionary(); var array = JArray.Parse(json); foreach (var obj in array) { if (obj is JObject jobj) { - jsonObjects.Add(jobj["id"].NotNull().Value().NotNull(), jobj.ToString()); + jsonObjects.TryAdd(jobj["id"].NotNull().Value().NotNull(), jobj.ToString()); } } return jsonObjects; diff --git a/tests/Speckle.Sdk.Serialization.Tests/SerializationTests.cs b/tests/Speckle.Sdk.Serialization.Tests/SerializationTests.cs index 64db5cb9..64c77603 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/SerializationTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/SerializationTests.cs @@ -1,13 +1,16 @@ using System.Collections.Concurrent; using FluentAssertions; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging.Abstractions; using Speckle.Newtonsoft.Json; using Speckle.Newtonsoft.Json.Linq; +using Speckle.Objects.Geometry; using Speckle.Sdk.Common; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Serialisation; using Speckle.Sdk.Serialisation.Utilities; +using Speckle.Sdk.Serialisation.V2; using Speckle.Sdk.Serialisation.V2.Receive; using Speckle.Sdk.Serialisation.V2.Send; using Speckle.Sdk.Serialization.Tests.Framework; @@ -17,32 +20,20 @@ namespace Speckle.Sdk.Serialization.Tests; public class SerializationTests { - private class TestLoader(string json) : IObjectLoader + private readonly ISerializeProcessFactory _factory; + + public SerializationTests() { - public Task<(Json, IReadOnlyCollection)> GetAndCache(string rootId, DeserializeProcessOptions? options) - { - var childrenIds = ClosureParser.GetChildrenIds(new(json), default).Select(x => new Id(x)).ToList(); - return Task.FromResult<(Json, IReadOnlyCollection)>((new(json), childrenIds)); - } + TypeLoader.Reset(); + TypeLoader.Initialize(typeof(Base).Assembly, typeof(Mesh).Assembly, typeof(TestClass).Assembly); - public string? LoadId(string id) => null; + var serviceCollection = new ServiceCollection(); + serviceCollection.AddSpeckleSdk(HostApplications.Navisworks, HostAppVersion.v2023, "Test"); + var serviceProvider = serviceCollection.BuildServiceProvider(); - public void Dispose() { } + _factory = serviceProvider.GetRequiredService(); } - /* - [Test] - [TestCase("RevitObject.json")] - public async Task RunTest2(string fileName) - { - var fullName = _assembly.GetManifestResourceNames().Single(x => x.EndsWith(fileName)); - var json = await ReadJson(fullName); - var closure = await ReadAsObjects(json); - using DeserializeProcess sut = new(null, new TestLoader(json), new TestTransport(closure)); - var @base = await sut.Deserialize("551513ff4f3596024547fc818f1f3f70"); - @base.Should().NotBeNull(); - }*/ - public class TestObjectLoader(IReadOnlyDictionary idToObject) : IObjectLoader { public Task<(Json, IReadOnlyCollection)> GetAndCache(string rootId, DeserializeProcessOptions? options) @@ -66,7 +57,7 @@ public class SerializationTests [InlineData("RevitObject.json.gz")] public async Task Basic_Namespace_Validation(string fileName) { - var closures = await TestFileManager.GetFileAsClosures(fileName); + var closures = TestFileManager.GetFileAsClosures(fileName); var deserializer = new SpeckleObjectDeserializer { ReadTransport = new TestTransport(closures), @@ -106,7 +97,7 @@ public class SerializationTests [InlineData("RevitObject.json.gz")] public async Task Basic_Namespace_Validation_New(string fileName) { - var closures = await TestFileManager.GetFileAsClosures(fileName); + var closures = TestFileManager.GetFileAsClosures(fileName); await using var process = new DeserializeProcess( new TestObjectLoader(closures), null, @@ -165,7 +156,7 @@ public class SerializationTests [InlineData("RevitObject.json.gz", "3416d3fe01c9196115514c4a2f41617b", 7818)] public async Task Roundtrip_Test_Old(string fileName, string _, int count) { - var closures = await TestFileManager.GetFileAsClosures(fileName); + var closures = TestFileManager.GetFileAsClosures(fileName); var deserializer = new SpeckleObjectDeserializer { ReadTransport = new TestTransport(closures), @@ -199,7 +190,7 @@ public class SerializationTests [InlineData("RevitObject.json.gz", "3416d3fe01c9196115514c4a2f41617b", 7818, 4674)] public async Task Roundtrip_Test_New(string fileName, string rootId, int oldCount, int newCount) { - var closures = await TestFileManager.GetFileAsClosures(fileName); + var closures = TestFileManager.GetFileAsClosures(fileName); closures.Count.Should().Be(oldCount); Base root; @@ -226,14 +217,12 @@ public class SerializationTests } var newIdToJson = new ConcurrentDictionary(); + await using ( - var serializeProcess = new SerializeProcess( + var serializeProcess = _factory.CreateSerializeProcess( + new ConcurrentDictionary(), + newIdToJson, null, - new DummySqLiteSendManager(), - new DummySendServerObjectManager(newIdToJson), - new BaseChildFinder(new BasePropertyGatherer()), - new BaseSerializer(new DummySqLiteSendManager(), new ObjectSerializerFactory(new BasePropertyGatherer())), - new NullLoggerFactory(), default, new SerializeProcessOptions(true, true, false, true) ) diff --git a/tests/Speckle.Sdk.Serialization.Tests/Speckle.Sdk.Serialization.Tests.csproj b/tests/Speckle.Sdk.Serialization.Tests/Speckle.Sdk.Serialization.Tests.csproj index 3f3689e8..bea3bd9b 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/Speckle.Sdk.Serialization.Tests.csproj +++ b/tests/Speckle.Sdk.Serialization.Tests/Speckle.Sdk.Serialization.Tests.csproj @@ -10,6 +10,7 @@ + diff --git a/tests/Speckle.Sdk.Serialization.Tests/packages.lock.json b/tests/Speckle.Sdk.Serialization.Tests/packages.lock.json index 1298d82a..a9c01cb6 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/packages.lock.json +++ b/tests/Speckle.Sdk.Serialization.Tests/packages.lock.json @@ -25,6 +25,15 @@ "System.Buffers": "4.6.0" } }, + "Microsoft.Extensions.DependencyInjection": { + "type": "Direct", + "requested": "[2.2.0, )", + "resolved": "2.2.0", + "contentHash": "MZtBIwfDFork5vfjpJdG5g8wuJFt7d/y3LOSVVtDK/76wlbtz6cjltfKHqLx2TKVqTj5/c41t77m1+h20zqtPA==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0" + } + }, "Microsoft.NET.Test.Sdk": { "type": "Direct", "requested": "[17.13.0, )", From d305fe59cb6829ae281e9b610ad8185c2aa5c6be Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 8 Apr 2025 10:49:31 +0100 Subject: [PATCH 3/3] feat(sdk) clean up registration of sdk to not be connector specific (#274) * First pass of ObjectSaver and better in-memory usage * fix some tests * add commit to match deserialize process * correct more tests * format * make a deserialize factory * fix tests? and format * use distinct * Fix mismerge * Fix serialization issues with tests * fix merges * follow copilot suggestions * remove disables * change registration to take strings and TypeLoader isn't public * remove unused transports * more test fixes * fmt * add Application object back --- src/Speckle.Sdk/Assemby.cs | 3 +- src/Speckle.Sdk/Host/HostAppVersion.cs | 24 ---- src/Speckle.Sdk/Host/HostApplication.cs | 13 -- src/Speckle.Sdk/Host/HostApplications.cs | 43 ------ src/Speckle.Sdk/Host/TypeLoader.cs | 4 +- src/Speckle.Sdk/ServiceRegistration.cs | 56 ++++++-- src/Speckle.Sdk/Transports/DiskTransport.cs | 128 ------------------ .../Program.cs | 7 +- .../CancellationTests.cs | 6 +- .../DetachedTests.cs | 6 +- .../ExceptionTests.cs | 6 +- .../ExplicitInterfaceTests.cs | 8 +- .../SerializationTests.cs | 5 +- .../TestServiceSetup.cs | 3 +- .../TestDataHelper.cs | 3 +- .../Host/HostApplicationTests.cs | 21 --- .../Serialisation/SimpleRoundTripTests.cs | 6 +- .../TestServiceSetup.cs | 6 +- .../Transports/DiskTransportTests.cs | 39 ------ 19 files changed, 65 insertions(+), 322 deletions(-) delete mode 100644 src/Speckle.Sdk/Host/HostAppVersion.cs delete mode 100644 src/Speckle.Sdk/Host/HostApplication.cs delete mode 100644 src/Speckle.Sdk/Host/HostApplications.cs delete mode 100644 src/Speckle.Sdk/Transports/DiskTransport.cs delete mode 100644 tests/Speckle.Sdk.Tests.Unit/Host/HostApplicationTests.cs delete mode 100644 tests/Speckle.Sdk.Tests.Unit/Transports/DiskTransportTests.cs diff --git a/src/Speckle.Sdk/Assemby.cs b/src/Speckle.Sdk/Assemby.cs index e64211a6..ea434378 100644 --- a/src/Speckle.Sdk/Assemby.cs +++ b/src/Speckle.Sdk/Assemby.cs @@ -1,3 +1,4 @@ using System.Runtime.CompilerServices; -[assembly: InternalsVisibleTo("Speckle.Sdk.Tests.Unit")] +[assembly: InternalsVisibleTo("Speckle.Objects.Tests.Unit")] +[assembly: InternalsVisibleTo("Speckle.Sdk.Tests.Performance")] diff --git a/src/Speckle.Sdk/Host/HostAppVersion.cs b/src/Speckle.Sdk/Host/HostAppVersion.cs deleted file mode 100644 index b18b1a9f..00000000 --- a/src/Speckle.Sdk/Host/HostAppVersion.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace Speckle.Sdk.Host; - -public enum HostAppVersion -{ - v3, - v6, - v7, - v8, - v2019, - v2020, - v2021, - v2022, - v2023, - v2024, - v2025, - v2026, - v21, - v22, - v25, - v26, - v715, - v716, - v717, -} diff --git a/src/Speckle.Sdk/Host/HostApplication.cs b/src/Speckle.Sdk/Host/HostApplication.cs deleted file mode 100644 index 3037f8a8..00000000 --- a/src/Speckle.Sdk/Host/HostApplication.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Speckle.Sdk.Host; - -public readonly struct HostApplication -{ - public string Name { get; } - public string Slug { get; } - - public HostApplication(string name, string slug) - { - Name = name; - Slug = slug; - } -} diff --git a/src/Speckle.Sdk/Host/HostApplications.cs b/src/Speckle.Sdk/Host/HostApplications.cs deleted file mode 100644 index 2abced0a..00000000 --- a/src/Speckle.Sdk/Host/HostApplications.cs +++ /dev/null @@ -1,43 +0,0 @@ -namespace Speckle.Sdk.Host; - -/// -/// List of Host Applications - their slugs should match our ghost tags and ci/cd slugs -/// -public static class HostApplications -{ - public static string GetVersion(HostAppVersion version) => version.ToString().TrimStart('v'); - - public static readonly HostApplication Rhino = new("Rhino", "rhino"), - Grasshopper = new("Grasshopper", "grasshopper"), - Revit = new("Revit", "revit"), - Dynamo = new("Dynamo", "dynamo"), - Unity = new("Unity", "unity"), - GSA = new("GSA", "gsa"), - Civil = new("Civil 3D", "civil3d"), - Civil3D = new("Civil 3D", "civil3d"), - AutoCAD = new("AutoCAD", "autocad"), - MicroStation = new("MicroStation", "microstation"), - OpenRoads = new("OpenRoads", "openroads"), - OpenRail = new("OpenRail", "openrail"), - OpenBuildings = new("OpenBuildings", "openbuildings"), - ETABS = new("ETABS", "etabs"), - SAP2000 = new("SAP2000", "sap2000"), - CSiBridge = new("CSiBridge", "csibridge"), - SAFE = new("SAFE", "safe"), - TeklaStructures = new("Tekla Structures", "teklastructures"), - Dxf = new("DXF Converter", "dxf"), - Excel = new("Excel", "excel"), - Unreal = new("Unreal", "unreal"), - PowerBI = new("Power BI", "powerbi"), - Blender = new("Blender", "blender"), - QGIS = new("QGIS", "qgis"), - ArcGIS = new("ArcGIS", "arcgis"), - SketchUp = new("SketchUp", "sketchup"), - Archicad = new("Archicad", "archicad"), - TopSolid = new("TopSolid", "topsolid"), - Python = new("Python", "python"), - NET = new(".NET", "net"), - Navisworks = new("Navisworks", "navisworks"), - AdvanceSteel = new("Advance Steel", "advancesteel"), - Other = new("Other", "other"); -} diff --git a/src/Speckle.Sdk/Host/TypeLoader.cs b/src/Speckle.Sdk/Host/TypeLoader.cs index 18159abe..bae0d151 100644 --- a/src/Speckle.Sdk/Host/TypeLoader.cs +++ b/src/Speckle.Sdk/Host/TypeLoader.cs @@ -5,9 +5,9 @@ using Speckle.Sdk.Models; namespace Speckle.Sdk.Host; -public record LoadedType(string Name, Type Type, List DeprecatedNames); +internal record LoadedType(string Name, Type Type, List DeprecatedNames); -public static class TypeLoader +internal static class TypeLoader { private static bool s_initialized; private static List s_availableTypes = new(); diff --git a/src/Speckle.Sdk/ServiceRegistration.cs b/src/Speckle.Sdk/ServiceRegistration.cs index 703810dc..259f733f 100644 --- a/src/Speckle.Sdk/ServiceRegistration.cs +++ b/src/Speckle.Sdk/ServiceRegistration.cs @@ -7,25 +7,65 @@ using Speckle.Sdk.Logging; namespace Speckle.Sdk; +public record Application(string Name, string Slug); + +public record SpeckleSdkOptions( + Application Application, + string ApplicationVersion, + string? SpeckleVersion, + IEnumerable? Assemblies +); + public static class ServiceRegistration { + private static string GetAssemblyVersion() => + Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "Unknown"; + public static IServiceCollection AddSpeckleSdk( this IServiceCollection serviceCollection, - HostApplication application, - HostAppVersion version, - string speckleVersion + Application application, + string applicationVersion, + string? speckleVersion = null, + IEnumerable? assemblies = null + ) => serviceCollection.AddSpeckleSdk(new(application, applicationVersion, speckleVersion, assemblies)); + + public static IServiceCollection AddSpeckleSdk( + this IServiceCollection serviceCollection, + Application application, + string applicationVersion, + string? speckleVersion, + params Assembly[] assemblies + ) => serviceCollection.AddSpeckleSdk(new(application, applicationVersion, speckleVersion, assemblies)); + + public static IServiceCollection AddSpeckleSdk( + this IServiceCollection serviceCollection, + Application application, + string applicationVersion, + params Assembly[] assemblies + ) => serviceCollection.AddSpeckleSdk(new(application, applicationVersion, null, assemblies)); + + public static IServiceCollection AddSpeckleSdk( + this IServiceCollection serviceCollection, + SpeckleSdkOptions speckleSdkOptions ) { + var currentAssembly = Assembly.GetExecutingAssembly(); + var allAssembles = speckleSdkOptions.Assemblies?.ToList() ?? []; + if (!allAssembles.Contains(currentAssembly)) + { + allAssembles.Add(currentAssembly); + } + TypeLoader.Reset(); + TypeLoader.Initialize(allAssembles.ToArray()); serviceCollection.AddLogging(); - string name = application.Name; serviceCollection.AddSingleton( new SpeckleApplication { - HostApplication = name, - SpeckleVersion = speckleVersion, - HostApplicationVersion = HostApplications.GetVersion(version), - Slug = application.Slug, + HostApplication = speckleSdkOptions.Application.Name, + HostApplicationVersion = speckleSdkOptions.ApplicationVersion, + Slug = speckleSdkOptions.Application.Slug, + SpeckleVersion = speckleSdkOptions.SpeckleVersion ?? GetAssemblyVersion(), } ); serviceCollection.TryAddSingleton(); diff --git a/src/Speckle.Sdk/Transports/DiskTransport.cs b/src/Speckle.Sdk/Transports/DiskTransport.cs deleted file mode 100644 index 2c60a36d..00000000 --- a/src/Speckle.Sdk/Transports/DiskTransport.cs +++ /dev/null @@ -1,128 +0,0 @@ -using System.Diagnostics; -using System.Text; -using Speckle.Sdk.Logging; - -namespace Speckle.Sdk.Transports; - -/// -/// Writes speckle objects to disk. -/// -public class DiskTransport : ICloneable, ITransport -{ - public DiskTransport(string? basePath = null) - { - basePath ??= Path.Combine(SpecklePathProvider.UserSpeckleFolderPath, "DiskTransportFiles"); - - RootPath = Path.Combine(basePath); - - Directory.CreateDirectory(RootPath); - } - - public string RootPath { get; set; } - - public object Clone() - { - return new DiskTransport - { - RootPath = RootPath, - CancellationToken = CancellationToken, - OnErrorAction = OnErrorAction, - OnProgressAction = OnProgressAction, - TransportName = TransportName, - }; - } - - public string TransportName { get; set; } = "Disk"; - - public Dictionary TransportContext => - new() - { - { "name", TransportName }, - { "type", GetType().Name }, - { "basePath", RootPath }, - }; - - public CancellationToken CancellationToken { get; set; } - - public IProgress? OnProgressAction { get; set; } - - public Action? OnErrorAction { get; set; } - - public int SavedObjectCount { get; private set; } - - public TimeSpan Elapsed { get; set; } = TimeSpan.Zero; - - public void BeginWrite() - { - SavedObjectCount = 0; - } - - public void EndWrite() { } - - public Task GetObject(string id) - { - CancellationToken.ThrowIfCancellationRequested(); - - var filePath = Path.Combine(RootPath, id); - if (File.Exists(filePath)) - { - return Task.FromResult(File.ReadAllText(filePath, Encoding.UTF8)); - } - - return Task.FromResult(null); - } - - public void SaveObject(string id, string serializedObject) - { - var stopwatch = Stopwatch.StartNew(); - CancellationToken.ThrowIfCancellationRequested(); - - var filePath = Path.Combine(RootPath, id); - if (File.Exists(filePath)) - { - return; - } - - try - { - File.WriteAllText(filePath, serializedObject, Encoding.UTF8); - } - catch (Exception ex) - { - throw new TransportException(this, $"Failed to write object {id} to disk", ex); - } - - SavedObjectCount++; - stopwatch.Stop(); - Elapsed += stopwatch.Elapsed; - } - - public Task WriteComplete() - { - return Task.CompletedTask; - } - - public async Task CopyObjectAndChildren(string id, ITransport targetTransport) - { - string res = await TransportHelpers - .CopyObjectAndChildrenAsync(id, this, targetTransport, CancellationToken) - .ConfigureAwait(false); - return res; - } - - public Task> HasObjects(IReadOnlyList objectIds) - { - Dictionary ret = new(); - foreach (string objectId in objectIds) - { - var filePath = Path.Combine(RootPath, objectId); - ret[objectId] = File.Exists(filePath); - } - return Task.FromResult(ret); - } - - public override string ToString() - { - return $"Disk Transport @{RootPath}"; - } -} diff --git a/tests/Speckle.Sdk.Serialization.Testing/Program.cs b/tests/Speckle.Sdk.Serialization.Testing/Program.cs index ca7a9d92..a0f2d95d 100644 --- a/tests/Speckle.Sdk.Serialization.Testing/Program.cs +++ b/tests/Speckle.Sdk.Serialization.Testing/Program.cs @@ -1,10 +1,7 @@ #pragma warning disable CA1506 -using System.Reflection; using Microsoft.Extensions.DependencyInjection; using Speckle.Sdk; using Speckle.Sdk.Credentials; -using Speckle.Sdk.Host; -using Speckle.Sdk.Models; using Speckle.Sdk.Serialisation.V2; using Speckle.Sdk.Serialisation.V2.Send; using Speckle.Sdk.Serialization.Testing; @@ -12,8 +9,6 @@ using Speckle.Sdk.Serialization.Testing; const bool skipCacheReceive = false; const bool skipCacheSendCheck = true; const bool skipCacheSendSave = false; -TypeLoader.Reset(); -TypeLoader.Initialize(typeof(Base).Assembly, Assembly.GetExecutingAssembly()); var url = "https://latest.speckle.systems/projects/a3ac1b2706/models/59d3b0f3c6"; //small? var streamId = "a3ac1b2706"; @@ -30,7 +25,7 @@ var streamId = "2099ac4b5f"; var rootId = "30fb4cbe6eb2202b9e7b4a4fcc3dd2b6";*/ var serviceCollection = new ServiceCollection(); -serviceCollection.AddSpeckleSdk(HostApplications.Navisworks, HostAppVersion.v2023, "Test"); +serviceCollection.AddSpeckleSdk(new("Tests", "test"), "v3"); var serviceProvider = serviceCollection.BuildServiceProvider(); Console.WriteLine("Attach"); diff --git a/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.cs b/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.cs index fba0327b..93e721d5 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.cs @@ -3,7 +3,6 @@ using FluentAssertions; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging.Abstractions; using Speckle.Objects.Geometry; -using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Serialisation; using Speckle.Sdk.Serialisation.V2; @@ -20,11 +19,8 @@ public class CancellationTests public CancellationTests() { - TypeLoader.Reset(); - TypeLoader.Initialize(typeof(Base).Assembly, typeof(TestClass).Assembly, typeof(Polyline).Assembly); - var serviceCollection = new ServiceCollection(); - serviceCollection.AddSpeckleSdk(HostApplications.Navisworks, HostAppVersion.v2023, "Test"); + serviceCollection.AddSpeckleSdk(new("Tests", "test"), "v3", typeof(TestClass).Assembly, typeof(Polyline).Assembly); var serviceProvider = serviceCollection.BuildServiceProvider(); _factory = serviceProvider.GetRequiredService(); diff --git a/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs b/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs index ce06d3cc..5bd3ef94 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs @@ -4,7 +4,6 @@ using FluentAssertions; using Microsoft.Extensions.DependencyInjection; using Speckle.Newtonsoft.Json.Linq; using Speckle.Objects.Geometry; -using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Serialisation; using Speckle.Sdk.Serialisation.V2; @@ -20,11 +19,8 @@ public class DetachedTests public DetachedTests() { - TypeLoader.Reset(); - TypeLoader.Initialize(typeof(Base).Assembly, typeof(DetachedTests).Assembly, typeof(Polyline).Assembly); - var serviceCollection = new ServiceCollection(); - serviceCollection.AddSpeckleSdk(HostApplications.Navisworks, HostAppVersion.v2023, "Test"); + serviceCollection.AddSpeckleSdk(new("Tests", "test"), "v3", typeof(TestClass).Assembly, typeof(Polyline).Assembly); var serviceProvider = serviceCollection.BuildServiceProvider(); _factory = serviceProvider.GetRequiredService(); diff --git a/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.cs b/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.cs index d31b80d1..01ce4c64 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.cs @@ -3,7 +3,6 @@ using FluentAssertions; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging.Abstractions; using Speckle.Objects.Geometry; -using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Serialisation; using Speckle.Sdk.Serialisation.V2; @@ -20,11 +19,8 @@ public class ExceptionTests public ExceptionTests() { - TypeLoader.Reset(); - TypeLoader.Initialize(typeof(Base).Assembly, typeof(DetachedTests).Assembly, typeof(Polyline).Assembly); - var serviceCollection = new ServiceCollection(); - serviceCollection.AddSpeckleSdk(HostApplications.Navisworks, HostAppVersion.v2023, "Test"); + serviceCollection.AddSpeckleSdk(new("Tests", "test"), "v3", typeof(TestClass).Assembly, typeof(Polyline).Assembly); var serviceProvider = serviceCollection.BuildServiceProvider(); _factory = serviceProvider.GetRequiredService(); diff --git a/tests/Speckle.Sdk.Serialization.Tests/ExplicitInterfaceTests.cs b/tests/Speckle.Sdk.Serialization.Tests/ExplicitInterfaceTests.cs index dc46b582..eddbd777 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/ExplicitInterfaceTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/ExplicitInterfaceTests.cs @@ -1,6 +1,5 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; using Microsoft.Extensions.DependencyInjection; -using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Serialisation; using Speckle.Sdk.Serialisation.V2; @@ -14,11 +13,8 @@ public class ExplicitInterfaceTests public ExplicitInterfaceTests() { - TypeLoader.Reset(); - TypeLoader.Initialize(typeof(Base).Assembly, typeof(TestClass).Assembly); - var serviceCollection = new ServiceCollection(); - serviceCollection.AddSpeckleSdk(HostApplications.Navisworks, HostAppVersion.v2023, "Test"); + serviceCollection.AddSpeckleSdk(new("Tests", "test"), "v3", typeof(TestClass).Assembly); var serviceProvider = serviceCollection.BuildServiceProvider(); _factory = serviceProvider.GetRequiredService(); diff --git a/tests/Speckle.Sdk.Serialization.Tests/SerializationTests.cs b/tests/Speckle.Sdk.Serialization.Tests/SerializationTests.cs index 64c77603..7a2f2c62 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/SerializationTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/SerializationTests.cs @@ -24,11 +24,8 @@ public class SerializationTests public SerializationTests() { - TypeLoader.Reset(); - TypeLoader.Initialize(typeof(Base).Assembly, typeof(Mesh).Assembly, typeof(TestClass).Assembly); - var serviceCollection = new ServiceCollection(); - serviceCollection.AddSpeckleSdk(HostApplications.Navisworks, HostAppVersion.v2023, "Test"); + serviceCollection.AddSpeckleSdk(new("Tests", "test"), "v3", typeof(TestClass).Assembly, typeof(Polyline).Assembly); var serviceProvider = serviceCollection.BuildServiceProvider(); _factory = serviceProvider.GetRequiredService(); diff --git a/tests/Speckle.Sdk.Tests.Integration/TestServiceSetup.cs b/tests/Speckle.Sdk.Tests.Integration/TestServiceSetup.cs index 30d44dff..c071ea36 100644 --- a/tests/Speckle.Sdk.Tests.Integration/TestServiceSetup.cs +++ b/tests/Speckle.Sdk.Tests.Integration/TestServiceSetup.cs @@ -1,5 +1,4 @@ using Microsoft.Extensions.DependencyInjection; -using Speckle.Sdk.Host; namespace Speckle.Sdk.Tests.Integration; @@ -8,7 +7,7 @@ public static class TestServiceSetup public static IServiceProvider GetServiceProvider() { var serviceCollection = new ServiceCollection(); - serviceCollection.AddSpeckleSdk(HostApplications.Navisworks, HostAppVersion.v2023, "Test"); + serviceCollection.AddSpeckleSdk(new("Tests", "test"), "v3"); return serviceCollection.BuildServiceProvider(); } } diff --git a/tests/Speckle.Sdk.Tests.Performance/TestDataHelper.cs b/tests/Speckle.Sdk.Tests.Performance/TestDataHelper.cs index 9ca4a397..a82dd5e0 100644 --- a/tests/Speckle.Sdk.Tests.Performance/TestDataHelper.cs +++ b/tests/Speckle.Sdk.Tests.Performance/TestDataHelper.cs @@ -2,7 +2,6 @@ using Microsoft.Extensions.DependencyInjection; using Speckle.Sdk.Api; using Speckle.Sdk.Credentials; -using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Transports; @@ -19,7 +18,7 @@ public sealed class TestDataHelper : IDisposable public TestDataHelper() { var serviceCollection = new ServiceCollection(); - serviceCollection.AddSpeckleSdk(HostApplications.Navisworks, HostAppVersion.v2023, "Test"); + serviceCollection.AddSpeckleSdk(new("Tests", "test"), "v3"); ServiceProvider = serviceCollection.BuildServiceProvider(); } diff --git a/tests/Speckle.Sdk.Tests.Unit/Host/HostApplicationTests.cs b/tests/Speckle.Sdk.Tests.Unit/Host/HostApplicationTests.cs deleted file mode 100644 index 288f5656..00000000 --- a/tests/Speckle.Sdk.Tests.Unit/Host/HostApplicationTests.cs +++ /dev/null @@ -1,21 +0,0 @@ -using FluentAssertions; -using Speckle.Sdk.Host; - -namespace Speckle.Sdk.Tests.Unit.Host; - -public class HostApplicationTests -{ - public static TheoryData HostAppVersionData => new(Enum.GetValues().ToList()); - - [Theory] - [MemberData(nameof(HostAppVersionData))] - public void HostAppVersionParsingTests(HostAppVersion appVersion) - { - // Assert that the string representation starts with 'v' - appVersion.ToString().StartsWith('v').Should().BeTrue(); - - // Assert that the parsed version is a positive integer - var version = HostApplications.GetVersion(appVersion); - int.Parse(version).Should().BePositive(); - } -} diff --git a/tests/Speckle.Sdk.Tests.Unit/Serialisation/SimpleRoundTripTests.cs b/tests/Speckle.Sdk.Tests.Unit/Serialisation/SimpleRoundTripTests.cs index 63c64a26..16d80a9e 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Serialisation/SimpleRoundTripTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Serialisation/SimpleRoundTripTests.cs @@ -1,8 +1,6 @@ -using System.Reflection; -using FluentAssertions; +using FluentAssertions; using Microsoft.Extensions.DependencyInjection; using Speckle.Sdk.Api; -using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Tests.Unit.Host; @@ -14,8 +12,6 @@ public class SimpleRoundTripTests public SimpleRoundTripTests() { - TypeLoader.Reset(); - TypeLoader.Initialize(typeof(Base).Assembly, Assembly.GetExecutingAssembly()); var serviceProvider = TestServiceSetup.GetServiceProvider(); _operations = serviceProvider.GetRequiredService(); } diff --git a/tests/Speckle.Sdk.Tests.Unit/TestServiceSetup.cs b/tests/Speckle.Sdk.Tests.Unit/TestServiceSetup.cs index 28493be0..bd6d4a39 100644 --- a/tests/Speckle.Sdk.Tests.Unit/TestServiceSetup.cs +++ b/tests/Speckle.Sdk.Tests.Unit/TestServiceSetup.cs @@ -1,5 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; -using Speckle.Sdk.Host; +using System.Reflection; +using Microsoft.Extensions.DependencyInjection; namespace Speckle.Sdk.Tests.Unit; @@ -8,7 +8,7 @@ public static class TestServiceSetup public static IServiceProvider GetServiceProvider() { var serviceCollection = new ServiceCollection(); - serviceCollection.AddSpeckleSdk(HostApplications.Navisworks, HostAppVersion.v2023, "Test"); + serviceCollection.AddSpeckleSdk(new("Tests", "test"), "v3", Assembly.GetExecutingAssembly()); return serviceCollection.BuildServiceProvider(); } } diff --git a/tests/Speckle.Sdk.Tests.Unit/Transports/DiskTransportTests.cs b/tests/Speckle.Sdk.Tests.Unit/Transports/DiskTransportTests.cs deleted file mode 100644 index 68e3d627..00000000 --- a/tests/Speckle.Sdk.Tests.Unit/Transports/DiskTransportTests.cs +++ /dev/null @@ -1,39 +0,0 @@ -using FluentAssertions; -using Speckle.Sdk.Common; -using Speckle.Sdk.Transports; - -namespace Speckle.Sdk.Tests.Unit.Transports; - -public sealed class DiskTransportTests : TransportTests, IDisposable -{ - private readonly DiskTransport _diskTransport; - private readonly string _basePath = $"./temp_{Guid.NewGuid()}"; - private const string ApplicationName = "Speckle Integration Tests"; - private readonly string _fullPath; - - protected override ITransport Sut => _diskTransport.NotNull(); - - public DiskTransportTests() - { - _fullPath = Path.Combine(_basePath, ApplicationName); - _diskTransport = new DiskTransport(_fullPath); - } - - [Fact] - public void DirectoryCreated_AfterInitialization() - { - // Act - var directoryExists = Directory.Exists(_fullPath); - - // Assert - directoryExists.Should().BeTrue(); - } - - public void Dispose() - { - if (Directory.Exists(_basePath)) - { - Directory.Delete(_basePath, true); - } - } -}