diff --git a/Directory.Packages.props b/Directory.Packages.props index b442fb0c..e7f38171 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,32 +1,34 @@ - + - + + - + - + + - + diff --git a/README.md b/README.md index 5a437272..b5cbd214 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Speckle | Sharp | SDK ### .NET SDK, Tests, and Objects -[![Codecov](https://codecov.io/gh/specklesystems/speckle-sharp-sdk/graph/badge.svg?token=TTM5OGr38m)](https://codecov.io/gh/specklesystems/speckle-sharp-sdk) +[![codecov](https://codecov.io/gh/specklesystems/speckle-sharp-sdk/branch/dev/graph/badge.svg?token=TTM5OGr38m)](https://codecov.io/gh/specklesystems/speckle-sharp-sdk) > [!WARNING] > This is an early beta release, not meant for use in production! We're working to stabilise the 3.0 API, and until then there will be breaking changes. You have been warned! diff --git a/build/Program.cs b/build/Program.cs index 8a59188d..3664b8a5 100644 --- a/build/Program.cs +++ b/build/Program.cs @@ -42,7 +42,7 @@ Target( Target( CLEAN, - ForEach("**/output"), + forEach: ["**/output"], dir => { IEnumerable GetDirectories(string d) @@ -68,13 +68,13 @@ Target( Target(RESTORE_TOOLS, () => RunAsync("dotnet", "tool restore")); -Target(FORMAT, DependsOn(RESTORE_TOOLS), () => RunAsync("dotnet", "csharpier --check .")); +Target(FORMAT, dependsOn: [RESTORE_TOOLS], () => RunAsync("dotnet", "csharpier --check .")); -Target(RESTORE, DependsOn(FORMAT), () => RunAsync("dotnet", "restore Speckle.Sdk.sln --locked-mode")); +Target(RESTORE, dependsOn: [FORMAT], () => RunAsync("dotnet", "restore Speckle.Sdk.sln --locked-mode")); Target( BUILD, - DependsOn(RESTORE), + dependsOn: [RESTORE], async () => { var (version, fileVersion) = await GetVersions().ConfigureAwait(false); @@ -89,7 +89,7 @@ Target( Target( TEST, - DependsOn(BUILD), + dependsOn: [BUILD], Glob.Files(".", "**/*.Tests.Unit.csproj").Concat(Glob.Files(".", "**/*.Tests.csproj")), async file => { @@ -103,7 +103,7 @@ Target( Target( INTEGRATION, - DependsOn(BUILD), + dependsOn: [BUILD], async () => { await RunAsync("docker", "compose -f docker-compose.yml up --wait").ConfigureAwait(false); @@ -170,7 +170,7 @@ Target( Target( PACK, - DependsOn(BUILD), + dependsOn: [TEST], async () => { { @@ -182,6 +182,6 @@ Target( } ); -Target("default", DependsOn(FORMAT, TEST, INTEGRATION), () => Console.WriteLine("Done!")); +Target("default", dependsOn: [FORMAT, TEST, INTEGRATION], () => Console.WriteLine("Done!")); await RunTargetsAndExitAsync(args).ConfigureAwait(true); diff --git a/build/packages.lock.json b/build/packages.lock.json index 29700b45..9f4394a9 100644 --- a/build/packages.lock.json +++ b/build/packages.lock.json @@ -4,9 +4,9 @@ "net8.0": { "Bullseye": { "type": "Direct", - "requested": "[5.0.0, )", - "resolved": "5.0.0", - "contentHash": "bqyt+m17ym+5aN45C5oZRAjuLDt8jKiCm/ys1XfymIXSkrTFwvI/QsbY3ucPSHDz7SF7uON7B57kXFv5H2k1ew==" + "requested": "[6.0.0, )", + "resolved": "6.0.0", + "contentHash": "vgwwXfzs7jJrskWH7saHRMgPzziq/e86QZNWY1MnMxd7e+De7E7EX4K3C7yrvaK9y02SJoLxNxcLG/q5qUAghw==" }, "Glob": { "type": "Direct", diff --git a/src/Speckle.Objects/Geometry/Brep.cs b/src/Speckle.Objects/Geometry/Brep.cs index df201c32..345bb3a1 100644 --- a/src/Speckle.Objects/Geometry/Brep.cs +++ b/src/Speckle.Objects/Geometry/Brep.cs @@ -3,7 +3,6 @@ using Speckle.Newtonsoft.Json; using Speckle.Objects.Other; using Speckle.Objects.Primitive; using Speckle.Sdk.Common; -using Speckle.Sdk.Host; using Speckle.Sdk.Models; namespace Speckle.Objects.Geometry; @@ -31,7 +30,7 @@ public class Brep : Base, IHasArea, IHasVolume, IHasBoundingBox, ITransformable< /// /// Gets or sets the flat list of numbers representing the 's surfaces. /// - [DetachProperty, SchemaIgnore, Chunkable(31250)] + [DetachProperty, Chunkable(31250)] public List SurfacesValue { get @@ -77,7 +76,7 @@ public class Brep : Base, IHasArea, IHasVolume, IHasBoundingBox, ITransformable< /// /// This is only used for the class serialisation/deserialisation. You should use instead. /// - [DetachProperty, SchemaIgnore, Chunkable(31250)] + [DetachProperty, Chunkable(31250)] public List Curve3DValues { get => CurveArrayEncodingExtensions.ToArray(Curve3D); @@ -102,7 +101,7 @@ public class Brep : Base, IHasArea, IHasVolume, IHasBoundingBox, ITransformable< /// /// This is only used for the class serialisation/deserialisation. You should use instead. /// - [DetachProperty, SchemaIgnore, Chunkable(31250)] + [DetachProperty, Chunkable(31250)] public List Curve2DValues { get => CurveArrayEncodingExtensions.ToArray(Curve2D); @@ -127,7 +126,7 @@ public class Brep : Base, IHasArea, IHasVolume, IHasBoundingBox, ITransformable< /// /// This is only used for the class serialisation/deserialisation. You should use instead. /// - [DetachProperty, SchemaIgnore, Chunkable(31250)] + [DetachProperty, Chunkable(31250)] public List VerticesValue { get @@ -167,7 +166,7 @@ public class Brep : Base, IHasArea, IHasVolume, IHasBoundingBox, ITransformable< /// /// This is only used for the class serialisation/deserialisation. You should use instead. /// - [DetachProperty, SchemaIgnore, Chunkable(62500)] + [DetachProperty, Chunkable(62500)] public List EdgesValue { get => @@ -241,7 +240,7 @@ public class Brep : Base, IHasArea, IHasVolume, IHasBoundingBox, ITransformable< /// /// This is only used for the class serialisation/deserialisation. You should use instead. /// - [DetachProperty, SchemaIgnore, Chunkable(62500)] + [DetachProperty, Chunkable(62500)] public List LoopsValue { get => @@ -297,7 +296,7 @@ public class Brep : Base, IHasArea, IHasVolume, IHasBoundingBox, ITransformable< /// /// This is only used for the class serialisation/deserialisation. You should use instead. /// - [DetachProperty, SchemaIgnore, Chunkable(62500)] + [DetachProperty, Chunkable(62500)] public List TrimsValue { get @@ -363,7 +362,7 @@ public class Brep : Base, IHasArea, IHasVolume, IHasBoundingBox, ITransformable< /// /// This is only used for the class serialisation/deserialisation. You should use instead. /// - [DetachProperty, SchemaIgnore, Chunkable(62500)] + [DetachProperty, Chunkable(62500)] public List FacesValue { get => 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/BatchExtensions.cs b/src/Speckle.Sdk.Dependencies/Serialization/BatchExtensions.cs index 6867204c..fd1856ad 100644 --- a/src/Speckle.Sdk.Dependencies/Serialization/BatchExtensions.cs +++ b/src/Speckle.Sdk.Dependencies/Serialization/BatchExtensions.cs @@ -19,13 +19,13 @@ public static class BatchExtensions public static void AddBatchItem(this IMemoryOwner batch, T item) where T : IHasByteSize => ((Batch)batch).Add(item); - public static int GetBatchSize(this IMemoryOwner batch, Action logAsWarning, int maxBatchSize) + public static int GetBatchSize(this IMemoryOwner batch, int maxBatchSize) where T : IHasByteSize { var currentSize = ((Batch)batch).BatchByteSize; if (currentSize > maxBatchSize) { - logAsWarning($"Batch size exceeded. Current size: {currentSize} bytes. Max size: {maxBatchSize} bytes."); + //doing this to say it's full since the channel reader only does full being equivalent return maxBatchSize; } diff --git a/src/Speckle.Sdk.Dependencies/Serialization/ChannelExtensions.cs b/src/Speckle.Sdk.Dependencies/Serialization/ChannelExtensions.cs index f8f3524c..4133f2eb 100644 --- a/src/Speckle.Sdk.Dependencies/Serialization/ChannelExtensions.cs +++ b/src/Speckle.Sdk.Dependencies/Serialization/ChannelExtensions.cs @@ -8,7 +8,6 @@ public static class ChannelExtensions { public static BatchingChannelReader> BatchByByteSize( this ChannelReader source, - Action logAsWarning, int batchSize, bool singleReader = false, bool allowSynchronousContinuations = false @@ -16,7 +15,6 @@ public static class ChannelExtensions where T : IHasByteSize => new SizeBatchingChannelReader( source ?? throw new ArgumentNullException(nameof(source)), - logAsWarning, batchSize, singleReader, allowSynchronousContinuations diff --git a/src/Speckle.Sdk.Dependencies/Serialization/ChannelSaver.cs b/src/Speckle.Sdk.Dependencies/Serialization/ChannelSaver.cs index 5bb65dba..b30f4608 100644 --- a/src/Speckle.Sdk.Dependencies/Serialization/ChannelSaver.cs +++ b/src/Speckle.Sdk.Dependencies/Serialization/ChannelSaver.cs @@ -5,7 +5,7 @@ using Speckle.Sdk.Serialisation.V2.Send; namespace Speckle.Sdk.Dependencies.Serialization; -public abstract class ChannelSaver(Action logAsWarning, CancellationToken cancellationToken) +public abstract class ChannelSaver where T : IHasByteSize { private const int SEND_CAPACITY = 500; @@ -16,8 +16,6 @@ public abstract class ChannelSaver(Action logAsWarning, CancellationT private const int MAX_CACHE_WRITE_PARALLELISM = 4; private const int MAX_CACHE_BATCH = 500; - private readonly CancellationTokenSource _cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - private readonly Channel _checkCacheChannel = Channel.CreateBounded( new BoundedChannelOptions(SEND_CAPACITY) { @@ -30,26 +28,26 @@ public abstract class ChannelSaver(Action logAsWarning, CancellationT _ => throw new NotImplementedException("Dropping items not supported.") ); - public Task Start() => + public Task Start(CancellationToken cancellationToken) => _checkCacheChannel - .Reader.BatchByByteSize(logAsWarning, HTTP_SEND_CHUNK_SIZE) + .Reader.BatchByByteSize(HTTP_SEND_CHUNK_SIZE) .WithTimeout(HTTP_BATCH_TIMEOUT) .PipeAsync( MAX_PARALLELISM_HTTP, async x => await SendToServer(x).ConfigureAwait(false), HTTP_CAPACITY, false, - _cts.Token + cancellationToken ) .Join() .Batch(MAX_CACHE_BATCH) .WithTimeout(HTTP_BATCH_TIMEOUT) - .ReadAllConcurrently(MAX_CACHE_WRITE_PARALLELISM, SaveToCache, _cts.Token) + .ReadAllConcurrently(MAX_CACHE_WRITE_PARALLELISM, SaveToCache, cancellationToken) .ContinueWith( t => { Exception? ex = t.Exception; - if (ex is null && t.Status is TaskStatus.Canceled && !_cts.Token.IsCancellationRequested) + if (ex is null && t.Status is TaskStatus.Canceled && !cancellationToken.IsCancellationRequested) { ex = new OperationCanceledException(); } @@ -60,25 +58,26 @@ public abstract class ChannelSaver(Action logAsWarning, CancellationT } _checkCacheChannel.Writer.TryComplete(ex); }, - _cts.Token, + cancellationToken, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Current ); - public async ValueTask Save(T item) + public void Save(T item, CancellationToken cancellationToken) { - if (Exception is not null || _cts.IsCancellationRequested) + if (Exception is not null || cancellationToken.IsCancellationRequested) { return; //don't save if we're already done through an error } - await _checkCacheChannel.Writer.WriteAsync(item).ConfigureAwait(false); + // ReSharper disable once MethodSupportsCancellation + _checkCacheChannel.Writer.TryWrite(item); } private async Task> SendToServer(IMemoryOwner batch) { try { - await SendToServer((Batch)batch).ConfigureAwait(false); + await SendToServerInternal((Batch)batch).ConfigureAwait(false); return batch; } #pragma warning disable CA1031 @@ -90,20 +89,6 @@ public abstract class ChannelSaver(Action logAsWarning, CancellationT } } - 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); @@ -118,13 +103,11 @@ public abstract class ChannelSaver(Action logAsWarning, CancellationT } } - protected Exception? Exception { get; set; } + public Exception? Exception { get; set; } private void RecordException(Exception ex) { Exception = ex; _checkCacheChannel.Writer.TryComplete(ex); - //cancel everything! - _cts.Cancel(); } } diff --git a/src/Speckle.Sdk.Dependencies/Serialization/SizeBatchingChannelReader.cs b/src/Speckle.Sdk.Dependencies/Serialization/SizeBatchingChannelReader.cs index 5596edd4..bf09e65d 100644 --- a/src/Speckle.Sdk.Dependencies/Serialization/SizeBatchingChannelReader.cs +++ b/src/Speckle.Sdk.Dependencies/Serialization/SizeBatchingChannelReader.cs @@ -11,7 +11,6 @@ public interface IHasByteSize public sealed class SizeBatchingChannelReader( ChannelReader source, - Action logAsWarning, int batchSize, bool singleReader, bool syncCont = false @@ -34,5 +33,5 @@ public sealed class SizeBatchingChannelReader( protected override void AddBatchItem(IMemoryOwner batch, T item) => batch.AddBatchItem(item); - protected override int GetBatchSize(IMemoryOwner batch) => batch.GetBatchSize(logAsWarning, _batchSize); + protected override int GetBatchSize(IMemoryOwner batch) => batch.GetBatchSize(_batchSize); } diff --git a/src/Speckle.Sdk.Dependencies/SpeckleHttpClientHandler.cs b/src/Speckle.Sdk.Dependencies/SpeckleHttpClientHandler.cs index 2070de4e..7df830c5 100644 --- a/src/Speckle.Sdk.Dependencies/SpeckleHttpClientHandler.cs +++ b/src/Speckle.Sdk.Dependencies/SpeckleHttpClientHandler.cs @@ -3,7 +3,7 @@ using Speckle.Sdk.Logging; namespace Speckle.Sdk.Helpers; -public sealed class SpeckleHttpClientHandler : DelegatingHandler +internal sealed class SpeckleHttpClientHandler : DelegatingHandler { private readonly IAsyncPolicy _resiliencePolicy; private readonly ISdkActivityFactory _activityFactory; diff --git a/src/Speckle.Sdk.Dependencies/SpeckleHttpClientHandlerFactory.cs b/src/Speckle.Sdk.Dependencies/SpeckleHttpClientHandlerFactory.cs index 908e9a94..26e397df 100644 --- a/src/Speckle.Sdk.Dependencies/SpeckleHttpClientHandlerFactory.cs +++ b/src/Speckle.Sdk.Dependencies/SpeckleHttpClientHandlerFactory.cs @@ -40,8 +40,13 @@ public sealed class SpeckleHttpClientHandlerFactory(ISdkActivityFactory activity return Policy.WrapAsync(retryPolicy, timeoutPolicy); } - public SpeckleHttpClientHandler Create( + public DelegatingHandler Create( HttpMessageHandler? innerHandler = null, int timeoutSeconds = DEFAULT_TIMEOUT_SECONDS - ) => new(innerHandler ?? new HttpClientHandler(), activityFactory, HttpAsyncPolicy(timeoutSeconds: timeoutSeconds)); + ) => + new SpeckleHttpClientHandler( + innerHandler ?? new HttpClientHandler(), + activityFactory, + HttpAsyncPolicy(timeoutSeconds: timeoutSeconds) + ); } diff --git a/src/Speckle.Sdk.Dependencies/packages.lock.json b/src/Speckle.Sdk.Dependencies/packages.lock.json index c0197ff7..516c518c 100644 --- a/src/Speckle.Sdk.Dependencies/packages.lock.json +++ b/src/Speckle.Sdk.Dependencies/packages.lock.json @@ -13,9 +13,9 @@ }, "Microsoft.Extensions.ObjectPool": { "type": "Direct", - "requested": "[9.0.1, )", - "resolved": "9.0.1", - "contentHash": "r64veU9uYILp6pYqfo3qzRab8zLMALvXZgT4VRY79tXMLu8X79uTlJ6nqPLtPIVhfCPXycRh8ILyFz/gGBDQdQ==" + "requested": "[9.0.3, )", + "resolved": "9.0.3", + "contentHash": "4uPdnj9hLRrb3ZSeVEDtwIm9nNrrT9vAXYC9o1/yTW8lGOPwTyI2QlkcICwYEGM1LESGTFidcPMFACznUZKbIQ==" }, "Microsoft.SourceLink.GitHub": { "type": "Direct", @@ -174,9 +174,9 @@ }, "Microsoft.Extensions.ObjectPool": { "type": "Direct", - "requested": "[9.0.1, )", - "resolved": "9.0.1", - "contentHash": "r64veU9uYILp6pYqfo3qzRab8zLMALvXZgT4VRY79tXMLu8X79uTlJ6nqPLtPIVhfCPXycRh8ILyFz/gGBDQdQ==" + "requested": "[9.0.3, )", + "resolved": "9.0.3", + "contentHash": "4uPdnj9hLRrb3ZSeVEDtwIm9nNrrT9vAXYC9o1/yTW8lGOPwTyI2QlkcICwYEGM1LESGTFidcPMFACznUZKbIQ==" }, "Microsoft.SourceLink.GitHub": { "type": "Direct", diff --git a/src/Speckle.Sdk/Api/GraphQL/Client.cs b/src/Speckle.Sdk/Api/GraphQL/Client.cs index d575e494..58d92ea5 100644 --- a/src/Speckle.Sdk/Api/GraphQL/Client.cs +++ b/src/Speckle.Sdk/Api/GraphQL/Client.cs @@ -4,6 +4,7 @@ using System.Reflection; using GraphQL; using GraphQL.Client.Http; using Microsoft.Extensions.Logging; +using Speckle.InterfaceGenerator; using Speckle.Newtonsoft.Json; using Speckle.Newtonsoft.Json.Serialization; using Speckle.Sdk.Api.GraphQL; @@ -16,8 +17,14 @@ using Speckle.Sdk.Logging; namespace Speckle.Sdk.Api; +public partial interface IClient : IDisposable +{ + GraphQLHttpClient GQLClient { get; } +} + [SuppressMessage("Maintainability", "CA1506:Avoid excessive class coupling", Justification = "Class needs refactor")] -public sealed class Client : ISpeckleGraphQLClient, IDisposable +[GenerateAutoInterface] +public sealed class Client : ISpeckleGraphQLClient, IClient { private readonly ILogger _logger; private readonly ISdkActivityFactory _activityFactory; @@ -37,6 +44,7 @@ public sealed class Client : ISpeckleGraphQLClient, IDisposable private HttpClient HttpClient { get; } + [AutoInterfaceIgnore] public GraphQLHttpClient GQLClient { get; } /// @@ -67,6 +75,7 @@ public sealed class Client : ISpeckleGraphQLClient, IDisposable GQLClient = CreateGraphQLClient(account, HttpClient); } + [AutoInterfaceIgnore] public void Dispose() { try @@ -132,6 +141,7 @@ public sealed class Client : ISpeckleGraphQLClient, IDisposable } } + [AutoInterfaceIgnore] IDisposable ISpeckleGraphQLClient.SubscribeTo(GraphQLRequest request, Action callback) => SubscribeTo(request, callback); diff --git a/src/Speckle.Sdk/Api/GraphQL/ClientFactory.cs b/src/Speckle.Sdk/Api/GraphQL/ClientFactory.cs index c2af3e78..1cdb7f17 100644 --- a/src/Speckle.Sdk/Api/GraphQL/ClientFactory.cs +++ b/src/Speckle.Sdk/Api/GraphQL/ClientFactory.cs @@ -14,6 +14,6 @@ public class ClientFactory( ISpeckleHttp speckleHttp ) : IClientFactory { - public Client Create(Account account) => - new(loggerFactory.CreateLogger(), activityFactory, application, speckleHttp, account); + public IClient Create(Account account) => + new Client(loggerFactory.CreateLogger(), activityFactory, application, speckleHttp, account); } diff --git a/src/Speckle.Sdk/Api/GraphQL/Enums/ProjectVisibility.cs b/src/Speckle.Sdk/Api/GraphQL/Enums/ProjectVisibility.cs index 5e4b1440..7bb78f78 100644 --- a/src/Speckle.Sdk/Api/GraphQL/Enums/ProjectVisibility.cs +++ b/src/Speckle.Sdk/Api/GraphQL/Enums/ProjectVisibility.cs @@ -2,7 +2,9 @@ public enum ProjectVisibility { - Private, - Public, - Unlisted, + Private = 0, + + [Obsolete("Use Unlisted instead", true)] + Public = 1, + Unlisted = 2, } 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/Assemby.cs b/src/Speckle.Sdk/Assemby.cs new file mode 100644 index 00000000..ea434378 --- /dev/null +++ b/src/Speckle.Sdk/Assemby.cs @@ -0,0 +1,4 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Speckle.Objects.Tests.Unit")] +[assembly: InternalsVisibleTo("Speckle.Sdk.Tests.Performance")] diff --git a/src/Speckle.Sdk/Helpers/SerializerIdWriter.cs b/src/Speckle.Sdk/Helpers/SerializerIdWriter.cs index 10dc3d03..e4b8f061 100644 --- a/src/Speckle.Sdk/Helpers/SerializerIdWriter.cs +++ b/src/Speckle.Sdk/Helpers/SerializerIdWriter.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Text; using Speckle.Newtonsoft.Json; using Speckle.Sdk.Dependencies; @@ -5,6 +6,8 @@ using Speckle.Sdk.Serialisation; namespace Speckle.Sdk.Helpers; +//just a wrapper around a lot of newtonsoft overloads +[ExcludeFromCodeCoverage] public sealed class SerializerIdWriter : JsonWriter { private readonly JsonWriter _jsonWriter; diff --git a/src/Speckle.Sdk/Helpers/Http.cs b/src/Speckle.Sdk/Helpers/SpeckleHttp.cs similarity index 92% rename from src/Speckle.Sdk/Helpers/Http.cs rename to src/Speckle.Sdk/Helpers/SpeckleHttp.cs index a468abd0..3cea1aa6 100644 --- a/src/Speckle.Sdk/Helpers/Http.cs +++ b/src/Speckle.Sdk/Helpers/SpeckleHttp.cs @@ -15,10 +15,15 @@ public class SpeckleHttp(ILogger logger, ISpeckleHttpClientHandlerF /// The URI that should be pinged /// Request to failed public async Task HttpPing(Uri uri) + { + using var httpClient = CreateHttpClient(); + return await HttpPing(uri, httpClient).ConfigureAwait(false); + } + + public async Task HttpPing(Uri uri, HttpClient httpClient) { try { - using var httpClient = CreateHttpClient(); HttpResponseMessage response = await httpClient.GetAsync(uri).ConfigureAwait(false); response.EnsureSuccessStatusCode(); logger.LogInformation("Successfully pinged {uri}", uri); diff --git a/src/Speckle.Sdk/Host/Attributes.cs b/src/Speckle.Sdk/Host/Attributes.cs deleted file mode 100644 index 5887f6af..00000000 --- a/src/Speckle.Sdk/Host/Attributes.cs +++ /dev/null @@ -1,63 +0,0 @@ -namespace Speckle.Sdk.Host; - -[AttributeUsage(AttributeTargets.Constructor)] -public sealed class SchemaInfoAttribute : Attribute -{ - public SchemaInfoAttribute(string name, string description) - : this(name, description, null, null) { } - - public SchemaInfoAttribute(string name, string description, string? category, string? subcategory) - { - Name = name; - Description = description; - Category = category; - Subcategory = subcategory; - } - - public string? Subcategory { get; } - - public string? Category { get; } - - public string Description { get; } - - public string Name { get; } -} - -[AttributeUsage(AttributeTargets.Constructor)] -public sealed class SchemaDeprecatedAttribute : Attribute { } - -[AttributeUsage(AttributeTargets.Parameter)] -public sealed class SchemaParamInfoAttribute : Attribute -{ - public SchemaParamInfoAttribute(string description) - { - Description = description; - } - - public string Description { get; } -} - -/// -/// Used to indicate which is the main input parameter of the schema builder component. Schema info will be attached to this object. -/// -[AttributeUsage(AttributeTargets.Parameter)] -public sealed class SchemaMainParamAttribute : Attribute { } - -// TODO: this could be nuked, as it's only used to hide props on Base, -// which we might want to expose anyways... -/// -/// Used to ignore properties from expand objects etc -/// -[AttributeUsage(AttributeTargets.Property)] -public sealed class SchemaIgnoreAttribute : Attribute { } - -[AttributeUsage(AttributeTargets.Method)] -public sealed class SchemaComputedAttribute : Attribute -{ - public SchemaComputedAttribute(string name) - { - Name = name; - } - - public string Name { get; } -} 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 fc38d763..00000000 --- a/src/Speckle.Sdk/Host/HostApplications.cs +++ /dev/null @@ -1,220 +0,0 @@ -using System.Diagnostics.Contracts; - -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"); - - /// - /// Gets a HostApplication form a string. It could be the versioned name or a string coming from a process running. - /// - /// String with the name of the app - /// - [Pure] - public static HostApplication GetHostAppFromString(string? appname) - { - if (appname == null) - { - return Other; - } - - appname = appname.ToLowerInvariant().Replace(" ", ""); - if (appname.Contains("dynamo")) - { - return Dynamo; - } - - if (appname.Contains("revit")) - { - return Revit; - } - - if (appname.Contains("autocad")) - { - return AutoCAD; - } - if (appname.Contains("civil3d")) - { - return Civil3D; - } - if (appname.Contains("civil")) - { - return Civil; - } - - if (appname.Contains("rhino")) - { - return Rhino; - } - - if (appname.Contains("grasshopper")) - { - return Grasshopper; - } - - if (appname.Contains("unity")) - { - return Unity; - } - - if (appname.Contains("gsa")) - { - return GSA; - } - - if (appname.Contains("microstation")) - { - return MicroStation; - } - - if (appname.Contains("openroads")) - { - return OpenRoads; - } - - if (appname.Contains("openrail")) - { - return OpenRail; - } - - if (appname.Contains("openbuildings")) - { - return OpenBuildings; - } - - if (appname.Contains("etabs")) - { - return ETABS; - } - - if (appname.Contains("sap")) - { - return SAP2000; - } - - if (appname.Contains("csibridge")) - { - return CSiBridge; - } - - if (appname.Contains("safe")) - { - return SAFE; - } - - if (appname.Contains("teklastructures")) - { - return TeklaStructures; - } - - if (appname.Contains("dxf")) - { - return Dxf; - } - - if (appname.Contains("excel")) - { - return Excel; - } - - if (appname.Contains("unreal")) - { - return Unreal; - } - - if (appname.Contains("powerbi")) - { - return PowerBI; - } - - if (appname.Contains("blender")) - { - return Blender; - } - - if (appname.Contains("qgis")) - { - return QGIS; - } - - if (appname.Contains("arcgis")) - { - return ArcGIS; - } - - if (appname.Contains("sketchup")) - { - return SketchUp; - } - - if (appname.Contains("archicad")) - { - return Archicad; - } - - if (appname.Contains("topsolid")) - { - return TopSolid; - } - - if (appname.Contains("python")) - { - return Python; - } - - if (appname.Contains("net")) - { - return NET; - } - - if (appname.Contains("navisworks")) - { - return Navisworks; - } - - if (appname.Contains("advancesteel")) - { - return AdvanceSteel; - } - - return new HostApplication(appname, appname); - } -} 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/Models/Base.cs b/src/Speckle.Sdk/Models/Base.cs index 45b8efed..33a4886a 100644 --- a/src/Speckle.Sdk/Models/Base.cs +++ b/src/Speckle.Sdk/Models/Base.cs @@ -28,20 +28,17 @@ public class Base : DynamicBase, ISpeckleObject /// /// A speckle object's id is an unique hash based on its properties. NOTE: this field will be null unless the object was deserialised from a source. Use the function to get it. /// - [SchemaIgnore] public virtual string? id { get; set; } /// /// Secondary, ideally host application driven, object identifier. /// - [SchemaIgnore] public string? applicationId { get; set; } /// /// Holds the type information of this speckle object, derived automatically /// from its assembly name and inheritance. /// - [SchemaIgnore] public virtual string speckle_type { get @@ -210,11 +207,7 @@ public class Base : DynamicBase, ISpeckleObject myDuplicate.id = id; myDuplicate.applicationId = applicationId; - foreach ( - var kvp in GetMembers( - DynamicBaseMemberType.Instance | DynamicBaseMemberType.Dynamic | DynamicBaseMemberType.SchemaIgnored - ) - ) + foreach (var kvp in GetMembers()) { var propertyInfo = type.GetProperty(kvp.Key); if (propertyInfo is not null && !propertyInfo.CanWrite) diff --git a/src/Speckle.Sdk/Models/DynamicBase.cs b/src/Speckle.Sdk/Models/DynamicBase.cs index 483bda4a..e7f3e953 100644 --- a/src/Speckle.Sdk/Models/DynamicBase.cs +++ b/src/Speckle.Sdk/Models/DynamicBase.cs @@ -1,7 +1,6 @@ using System.Dynamic; using System.Reflection; using Speckle.Newtonsoft.Json; -using Speckle.Sdk.Common; using Speckle.Sdk.Host; namespace Speckle.Sdk.Models; @@ -233,16 +232,12 @@ public class DynamicBase : DynamicObject, IDynamicMetaObjectProvider .GetBaseProperties(GetType()) .Where(x => { - var hasIgnored = x.IsDefined(typeof(SchemaIgnoreAttribute), true); var hasObsolete = x.IsDefined(typeof(ObsoleteAttribute), true); // If obsolete is false and prop has obsolete attr // OR // If schemaIgnored is true and prop has schemaIgnore attr - return !( - !includeMembers.HasFlag(DynamicBaseMemberType.SchemaIgnored) && hasIgnored - || !includeMembers.HasFlag(DynamicBaseMemberType.Obsolete) && hasObsolete - ); + return !(!includeMembers.HasFlag(DynamicBaseMemberType.Obsolete) && hasObsolete); }); foreach (var pi in pinfos) { @@ -252,20 +247,6 @@ public class DynamicBase : DynamicObject, IDynamicMetaObjectProvider } } } - - if (includeMembers.HasFlag(DynamicBaseMemberType.SchemaComputed)) - { - GetType() - .GetMethods() - .Where(e => e.IsDefined(typeof(SchemaComputedAttribute)) && !e.IsDefined(typeof(ObsoleteAttribute))) - .ToList() - .ForEach(e => - { - var attr = e.GetCustomAttribute().NotNull(); - dic[attr.Name] = e.Invoke(this, null); - }); - } - return dic; } diff --git a/src/Speckle.Sdk/Models/DynamicBaseMemberType.cs b/src/Speckle.Sdk/Models/DynamicBaseMemberType.cs index 3403bf2a..fc114380 100644 --- a/src/Speckle.Sdk/Models/DynamicBaseMemberType.cs +++ b/src/Speckle.Sdk/Models/DynamicBaseMemberType.cs @@ -1,5 +1,3 @@ -using Speckle.Sdk.Host; - namespace Speckle.Sdk.Models; /// @@ -23,23 +21,18 @@ public enum DynamicBaseMemberType /// Obsolete = 4, - /// - /// The typed members flagged with attribute. - /// - SchemaIgnored = 8, - /// /// The typed methods flagged with TODO: /// SchemaComputed = 16, /// - /// All the typed members, including ones with or attributes. + /// All the typed members, including ones with attributes. /// - InstanceAll = Instance + Obsolete + SchemaIgnored, + InstanceAll = Instance + Obsolete, /// - /// All the members, including dynamic and instance members flagged with or attributes + /// All the members, including dynamic and instance members flagged with attributes /// All = InstanceAll + Dynamic, } 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/PriorityScheduler.cs b/src/Speckle.Sdk/Serialisation/V2/PriorityScheduler.cs index a1fd670a..d58c5ece 100644 --- a/src/Speckle.Sdk/Serialisation/V2/PriorityScheduler.cs +++ b/src/Speckle.Sdk/Serialisation/V2/PriorityScheduler.cs @@ -6,8 +6,7 @@ namespace Speckle.Sdk.Serialisation.V2; public sealed class PriorityScheduler( ILogger logger, ThreadPriority priority, - int maximumConcurrencyLevel, - CancellationToken cancellationToken + int maximumConcurrencyLevel ) : TaskScheduler, IAsyncDisposable { private readonly BlockingCollection _tasks = new(); @@ -56,7 +55,7 @@ public sealed class PriorityScheduler( while (true) { //we're done so leave - if (_tasks.IsCompleted || cancellationToken.IsCancellationRequested) + if (_tasks.IsCompleted) { break; } @@ -66,11 +65,6 @@ public sealed class PriorityScheduler( { break; } - //cancelled just leave - if (cancellationToken.IsCancellationRequested) - { - break; - } //didn't get a task but just timed out so continue if (!success) { diff --git a/src/Speckle.Sdk/Serialisation/V2/Receive/DeserializeProcess.cs b/src/Speckle.Sdk/Serialisation/V2/Receive/DeserializeProcess.cs index e0e62922..6a2714e0 100644 --- a/src/Speckle.Sdk/Serialisation/V2/Receive/DeserializeProcess.cs +++ b/src/Speckle.Sdk/Serialisation/V2/Receive/DeserializeProcess.cs @@ -54,8 +54,7 @@ public sealed class DeserializeProcess( private readonly PriorityScheduler _belowNormal = new( loggerFactory.CreateLogger(), ThreadPriority.BelowNormal, - Environment.ProcessorCount * 2, - cancellationToken + Environment.ProcessorCount * 2 ); private readonly DeserializeProcessOptions _options = options ?? new(); diff --git a/src/Speckle.Sdk/Serialisation/V2/Send/BaseItem.cs b/src/Speckle.Sdk/Serialisation/V2/Send/BaseItem.cs index f5c39f4b..2a88e3db 100644 --- a/src/Speckle.Sdk/Serialisation/V2/Send/BaseItem.cs +++ b/src/Speckle.Sdk/Serialisation/V2/Send/BaseItem.cs @@ -2,8 +2,7 @@ using System.Text; namespace Speckle.Sdk.Serialisation.V2.Send; -public readonly record struct BaseItem(Id Id, Json Json, bool NeedsStorage, Dictionary? Closures) - : IHasByteSize +public sealed record BaseItem(Id Id, Json Json, bool NeedsStorage, Dictionary? Closures) : IHasByteSize { public int ByteSize { get; } = Encoding.UTF8.GetByteCount(Json.Value); @@ -13,7 +12,7 @@ public readonly record struct BaseItem(Id Id, Json Json, bool NeedsStorage, Dict { return false; } - return string.Equals(Id.Value, other.Value.Id.Value, StringComparison.OrdinalIgnoreCase); + return string.Equals(Id.Value, other.Id.Value, StringComparison.OrdinalIgnoreCase); } public override int GetHashCode() => Id.GetHashCode(); diff --git a/src/Speckle.Sdk/Serialisation/V2/Send/EmptyDictionary.cs b/src/Speckle.Sdk/Serialisation/V2/Send/EmptyDictionary.cs deleted file mode 100644 index 7059231a..00000000 --- a/src/Speckle.Sdk/Serialisation/V2/Send/EmptyDictionary.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System.Collections; -using System.Diagnostics.CodeAnalysis; - -namespace Speckle.Sdk.Serialisation.V2.Send; - -public class EmptyDictionary : IDictionary -{ - public IEnumerator> GetEnumerator() => throw new NotImplementedException(); - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - - public void Add(KeyValuePair item) { } - - public void Clear() => throw new NotImplementedException(); - - public bool Contains(KeyValuePair item) => false; - - public void CopyTo(KeyValuePair[] array, int arrayIndex) => throw new NotImplementedException(); - - public bool Remove(KeyValuePair item) => false; - - public int Count => 0; - public bool IsReadOnly => false; - - public void Add(TKey key, TValue value) { } - - public bool ContainsKey(TKey key) => false; - - public bool Remove(TKey key) => false; - - public bool TryGetValue(TKey key, [UnscopedRef] out TValue value) - { - value = default!; - return false; - } - - public TValue this[TKey key] - { -#pragma warning disable CA1065 - get => throw new NotImplementedException(); -#pragma warning restore CA1065 - set { } - } - - public ICollection Keys { get; } - public ICollection Values { get; } -} 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 50fff486..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,28 +26,27 @@ 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 -#pragma warning disable CS9107 -#pragma warning disable CA2254 -) - : ChannelSaver(x => loggerFactory.CreateLogger().LogWarning(x), cancellationToken), - ISerializeProcess -#pragma warning restore CA2254 -#pragma warning restore CS9107 +) : 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")] private readonly PriorityScheduler _highest = new( loggerFactory.CreateLogger(), ThreadPriority.Highest, - 2, - cancellationToken + 2 ); //async dispose @@ -57,12 +54,9 @@ public sealed class SerializeProcess( private readonly PriorityScheduler _belowNormal = new( loggerFactory.CreateLogger(), ThreadPriority.BelowNormal, - Environment.ProcessorCount * 2, - cancellationToken + 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< @@ -75,26 +69,24 @@ 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(); } - public void ThrowIfFailed() + private void ThrowIfFailed() { - //always check for cancellation first - cancellationToken.ThrowIfCancellationRequested(); - if (Exception is not null) + //order here matters...null with cancellation means a user did it, otherwise it's a real Exception + if (objectSaver.Exception is not null) { - throw new SpeckleException("Error while sending", Exception); + throw new SpeckleException("Error while sending", objectSaver.Exception); } + _processSource.Token.ThrowIfCancellationRequested(); } private async Task WaitForSchedulerCompletion() @@ -107,24 +99,25 @@ public sealed class SerializeProcess( { try { - var channelTask = Start(); + var channelTask = objectSaver.Start(_processSource.Token); var findTotalObjectsTask = Task.CompletedTask; if (!_options.SkipFindTotalObjects) { ThrowIfFailed(); findTotalObjectsTask = Task.Factory.StartNew( () => TraverseTotal(root), - cancellationToken, + _processSource.Token, TaskCreationOptions.AttachedToParent | TaskCreationOptions.PreferFairness, _highest ); } - await Traverse(root).ConfigureAwait(false); - DoneTraversing(); + await Traverse(root, _processSource.Token).ConfigureAwait(false); + ThrowIfFailed(); + 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(); @@ -139,6 +132,10 @@ public sealed class SerializeProcess( private void TraverseTotal(Base obj) { + if (_processSource.Token.IsCancellationRequested) + { + return; + } foreach (var child in baseChildFinder.GetChildren(obj)) { _objectsFound++; @@ -147,116 +144,144 @@ public sealed class SerializeProcess( } } - private async Task> Traverse(Base obj) + private async Task> Traverse(Base obj, CancellationToken token) { - var tasks = new List>>(); - foreach (var child in baseChildFinder.GetChildren(obj)) + if (token.IsCancellationRequested) { - // tmp is necessary because of the way closures close over loop variables - var tmp = child; - cancellationToken.ThrowIfCancellationRequested(); - var t = Task - .Factory.StartNew( - async () => await Traverse(tmp).ConfigureAwait(false), - cancellationToken, - TaskCreationOptions.AttachedToParent | TaskCreationOptions.PreferFairness, - _belowNormal - ) - .Unwrap(); - tasks.Add(t); + return EMPTY_CLOSURES; } - Dictionary[] taskClosures = []; - if (tasks.Count > 0) - { - taskClosures = await Task.WhenAll(tasks).ConfigureAwait(false); - } - var childClosures = _childClosurePool.Get(); - foreach (var childClosure in taskClosures) - { - foreach (var kvp in childClosure) - { - childClosures[kvp.Key] = kvp.Value; - } - _currentClosurePool.Return(childClosure); - } - - var items = baseSerializer.Serialise(obj, childClosures, _options.SkipCacheRead, cancellationToken); - - var currentClosures = _currentClosurePool.Get(); - Interlocked.Increment(ref _objectCount); - progress?.Report(new(ProgressEvent.FromCacheOrSerialized, _objectCount, Math.Max(_objectCount, _objectsFound))); - foreach (var item in items) - { - if (item.NeedsStorage) - { - Interlocked.Increment(ref _objectsSerialized); - await Save(item).ConfigureAwait(false); - } - - if (!currentClosures.ContainsKey(item.Id)) - { - currentClosures.Add(item.Id, new NodeInfo(item.Json, item.Closures)); - } - } - _childClosurePool.Return(childClosures); - return currentClosures; - } - - protected override async Task SendToServerInternal(Batch batch) - { try { - if (!_options.SkipServer && batch.Items.Count != 0) + var tasks = new List>>(); + using var childCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(token); + foreach (var child in baseChildFinder.GetChildren(obj)) { - var objectBatch = batch.Items.Distinct().ToList(); - var hasObjects = await serverObjectManager - .HasObjects(objectBatch.Select(x => x.Id.Value).Freeze(), cancellationToken) - .ConfigureAwait(false); - objectBatch = batch.Items.Where(x => !hasObjects[x.Id.Value]).ToList(); - if (objectBatch.Count != 0) + // tmp is necessary because of the way closures close over loop variables + var tmp = child; + if (token.IsCancellationRequested) { - await serverObjectManager.UploadObjects(objectBatch, true, progress, cancellationToken).ConfigureAwait(false); - Interlocked.Exchange(ref _uploaded, _uploaded + batch.Items.Count); + return EMPTY_CLOSURES; + } + var t = Task + .Factory.StartNew( + // ReSharper disable once AccessToDisposedClosure + // don't need to capture here + async () => await Traverse(tmp, childCancellationTokenSource.Token).ConfigureAwait(false), + childCancellationTokenSource.Token, + TaskCreationOptions.AttachedToParent | TaskCreationOptions.PreferFairness, + _belowNormal + ) + .Unwrap(); + tasks.Add(t); + } + + if (token.IsCancellationRequested) + { + return EMPTY_CLOSURES; + } + + List> taskClosures = new(); + if (tasks.Count > 0) + { + var currentTasks = tasks.ToList(); + do + { + //grab when any Task is done and see if we're cancelling + var t = await Task.WhenAny(currentTasks).ConfigureAwait(false); + if (t.IsCanceled) + { + return EMPTY_CLOSURES; + } + if (t.IsFaulted) + { + if (t.Exception is not null) + { + RecordException(t.Exception); + } + return EMPTY_CLOSURES; + } + taskClosures.Add(t.Result); + currentTasks.Remove(t); + } while (currentTasks.Count > 0); + } + + if (token.IsCancellationRequested) + { + return EMPTY_CLOSURES; + } + + var childClosures = _childClosurePool.Get(); + foreach (var childClosure in taskClosures) + { + foreach (var kvp in childClosure) + { + childClosures[kvp.Key] = kvp.Value; } - progress?.Report(new(ProgressEvent.UploadedObjects, _uploaded, null)); + _currentClosurePool.Return(childClosure); } + + if (token.IsCancellationRequested) + { + return EMPTY_CLOSURES; + } + + var items = baseSerializer.Serialise(obj, childClosures, _options.SkipCacheRead, token); + if (token.IsCancellationRequested) + { + return EMPTY_CLOSURES; + } + + var currentClosures = _currentClosurePool.Get(); + try + { + Interlocked.Increment(ref _objectCount); + progress?.Report(new(ProgressEvent.FromCacheOrSerialized, _objectCount, Math.Max(_objectCount, _objectsFound))); + foreach (var item in items) + { + if (item.NeedsStorage) + { + if (token.IsCancellationRequested) + { + return EMPTY_CLOSURES; + } + + Interlocked.Increment(ref _objectsSerialized); + objectSaver.SaveItem(item, childCancellationTokenSource.Token); + } + + if (!currentClosures.ContainsKey(item.Id)) + { + currentClosures.Add(item.Id, new NodeInfo(item.Json, item.Closures)); + } + } + } + finally + { + _childClosurePool.Return(childClosures); + } + + return currentClosures; } catch (OperationCanceledException) { - throw; + return EMPTY_CLOSURES; } #pragma warning disable CA1031 catch (Exception e) #pragma warning restore CA1031 { - _logger.LogError(e, "Error sending objects to server"); - throw; + RecordException(e); + return EMPTY_CLOSURES; } } - public override void SaveToCache(List batch) + private void RecordException(Exception e) { - 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) - { - throw; - } -#pragma warning disable CA1031 - catch (Exception e) -#pragma warning restore CA1031 - { - _logger.LogError(e, "Error sending objects to server"); - throw; - } + //order here matters + _logger.LogError(e, "Error in SDK"); + 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/src/Speckle.Sdk/Serialisation/V2/ServerObjectManager.cs b/src/Speckle.Sdk/Serialisation/V2/ServerObjectManager.cs index 895a4a6f..e196c890 100644 --- a/src/Speckle.Sdk/Serialisation/V2/ServerObjectManager.cs +++ b/src/Speckle.Sdk/Serialisation/V2/ServerObjectManager.cs @@ -13,6 +13,12 @@ using Speckle.Sdk.Transports.ServerUtils; namespace Speckle.Sdk.Serialisation.V2; +public class ServerObjectManagerOptions(TimeSpan? timeout = null, string? boundary = null) +{ + public TimeSpan Timeout => timeout ?? TimeSpan.FromSeconds(120); + public string Boundary => boundary ??= Guid.NewGuid().ToString(); +} + [GenerateAutoInterface] public class ServerObjectManager : IServerObjectManager { @@ -21,6 +27,7 @@ public class ServerObjectManager : IServerObjectManager private readonly ISdkActivityFactory _activityFactory; private readonly HttpClient _client; private readonly string _streamId; + private readonly ServerObjectManagerOptions _serverObjectManagerOptions; public ServerObjectManager( ISpeckleHttp speckleHttp, @@ -28,13 +35,14 @@ public class ServerObjectManager : IServerObjectManager Uri baseUri, string streamId, string? authorizationToken, - int timeoutSeconds = 120 + ServerObjectManagerOptions? options = null ) { + _serverObjectManagerOptions = options ?? new(); _activityFactory = activityFactory; _client = speckleHttp.CreateHttpClient( new HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip }, - timeoutSeconds: timeoutSeconds, + timeoutSeconds: (int)_serverObjectManagerOptions.Timeout.TotalSeconds, authorizationToken: authorizationToken ); _client.BaseAddress = baseUri; @@ -139,10 +147,8 @@ public class ServerObjectManager : IServerObjectManager CancellationToken cancellationToken ) { + using var _ = _activityFactory.Start(); cancellationToken.ThrowIfCancellationRequested(); - - // Stopwatch sw = new Stopwatch(); sw.Start(); - string objectsPostParameter = JsonConvert.SerializeObject(objectIds); var payload = new Dictionary { { "objects", objectsPostParameter } }; string serializedPayload = JsonConvert.SerializeObject(payload); @@ -169,6 +175,7 @@ public class ServerObjectManager : IServerObjectManager CancellationToken cancellationToken ) { + using var _ = _activityFactory.Start(); cancellationToken.ThrowIfCancellationRequested(); using HttpRequestMessage message = new() @@ -177,7 +184,7 @@ public class ServerObjectManager : IServerObjectManager Method = HttpMethod.Post, }; - MultipartFormDataContent multipart = new(); + MultipartFormDataContent multipart = new(_serverObjectManagerOptions.Boundary); int mpId = 0; var ctBuilder = new StringBuilder("["); diff --git a/src/Speckle.Sdk/Serialisation/V2/ServerObjectManagerFactory.cs b/src/Speckle.Sdk/Serialisation/V2/ServerObjectManagerFactory.cs index 071a62b5..0fba82bf 100644 --- a/src/Speckle.Sdk/Serialisation/V2/ServerObjectManagerFactory.cs +++ b/src/Speckle.Sdk/Serialisation/V2/ServerObjectManagerFactory.cs @@ -8,6 +8,13 @@ namespace Speckle.Sdk.Serialisation.V2; public class ServerObjectManagerFactory(ISpeckleHttp speckleHttp, ISdkActivityFactory activityFactory) : IServerObjectManagerFactory { - public IServerObjectManager Create(Uri url, string streamId, string? authorizationToken, int timeoutSeconds = 120) => - new ServerObjectManager(speckleHttp, activityFactory, url, streamId, authorizationToken, timeoutSeconds); + public IServerObjectManager Create(Uri url, string streamId, string? authorizationToken, TimeSpan? timeout = null) => + new ServerObjectManager( + speckleHttp, + activityFactory, + url, + streamId, + authorizationToken, + new ServerObjectManagerOptions(timeout: timeout) + ); } 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.Objects.Tests.Unit/Module.cs b/tests/Speckle.Objects.Tests.Unit/Module.cs index 999f2e69..90adcf73 100644 --- a/tests/Speckle.Objects.Tests.Unit/Module.cs +++ b/tests/Speckle.Objects.Tests.Unit/Module.cs @@ -1,6 +1,7 @@ using System.Runtime.CompilerServices; using Speckle.Objects.Geometry; using Speckle.Sdk.Host; +using Speckle.Sdk.Models; using Speckle.Sdk.Testing; namespace Speckle.Objects.Tests.Unit; @@ -12,6 +13,6 @@ public static class Module { SpeckleVerify.Initialize(); TypeLoader.Reset(); - TypeLoader.Initialize(typeof(Polyline).Assembly); + TypeLoader.Initialize(typeof(Base).Assembly, typeof(Polyline).Assembly); } } diff --git a/tests/Speckle.Objects.Tests.Unit/Serialization/ObjectsSerializationTest.SerializeAndVerify_testCase=Speckle.Objects.Geometry.Mesh.verified.json b/tests/Speckle.Objects.Tests.Unit/Serialization/ObjectsSerializationTest.SerializeAndVerify_testCase=Speckle.Objects.Geometry.Mesh.verified.json new file mode 100644 index 00000000..19724719 --- /dev/null +++ b/tests/Speckle.Objects.Tests.Unit/Serialization/ObjectsSerializationTest.SerializeAndVerify_testCase=Speckle.Objects.Geometry.Mesh.verified.json @@ -0,0 +1,76 @@ +[ + { + "applicationId": null, + "data": [ + 3, + 0, + 1, + 2 + ], + "id": "13da8e855141b835e68bba721411046e", + "speckle_type": "Speckle.Core.Models.DataChunk" + }, + { + "__closure": { + "13da8e855141b835e68bba721411046e": 100, + "cc9d42395b317ed25947b1285bbd5103": 100, + "ede4848fc3abda9275a19fee3447ffbd": 100 + }, + "applicationId": "asdfasdf", + "area": 42.0, + "bbox": null, + "colors": [ + { + "__closure": null, + "referencedId": "cc9d42395b317ed25947b1285bbd5103", + "speckle_type": "reference" + } + ], + "faces": [ + { + "__closure": null, + "referencedId": "13da8e855141b835e68bba721411046e", + "speckle_type": "reference" + } + ], + "id": "85fdad62ca935832449ffb359ebed7b8", + "speckle_type": "Objects.Geometry.Mesh", + "textureCoordinates": [], + "units": "m", + "vertexNormals": [], + "vertices": [ + { + "__closure": null, + "referencedId": "ede4848fc3abda9275a19fee3447ffbd", + "speckle_type": "reference" + } + ], + "volume": 420.0 + }, + { + "applicationId": null, + "data": [ + -10185235, + -10185235, + -10185235 + ], + "id": "cc9d42395b317ed25947b1285bbd5103", + "speckle_type": "Speckle.Core.Models.DataChunk" + }, + { + "applicationId": null, + "data": [ + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 1.0, + 1.0, + 0.0 + ], + "id": "ede4848fc3abda9275a19fee3447ffbd", + "speckle_type": "Speckle.Core.Models.DataChunk" + } +] diff --git a/tests/Speckle.Objects.Tests.Unit/Serialization/ObjectsSerializationTest.SerializeAndVerify_testCase=Speckle.Objects.Geometry.Point.verified.json b/tests/Speckle.Objects.Tests.Unit/Serialization/ObjectsSerializationTest.SerializeAndVerify_testCase=Speckle.Objects.Geometry.Point.verified.json new file mode 100644 index 00000000..5d326b0d --- /dev/null +++ b/tests/Speckle.Objects.Tests.Unit/Serialization/ObjectsSerializationTest.SerializeAndVerify_testCase=Speckle.Objects.Geometry.Point.verified.json @@ -0,0 +1,11 @@ +[ + { + "applicationId": "iosdf;juasdfioj", + "id": "035cad79be39e59c765b7946c4ea5f0c", + "speckle_type": "Objects.Geometry.Point", + "units": "ft", + "x": 123.123, + "y": 111.222, + "z": -0.001 + } +] \ No newline at end of file diff --git a/tests/Speckle.Objects.Tests.Unit/Serialization/ObjectsSerializationTest.SerializeAndVerify_testCase=Speckle.Objects.Geometry.Vector.verified.json b/tests/Speckle.Objects.Tests.Unit/Serialization/ObjectsSerializationTest.SerializeAndVerify_testCase=Speckle.Objects.Geometry.Vector.verified.json new file mode 100644 index 00000000..5eb1d8cd --- /dev/null +++ b/tests/Speckle.Objects.Tests.Unit/Serialization/ObjectsSerializationTest.SerializeAndVerify_testCase=Speckle.Objects.Geometry.Vector.verified.json @@ -0,0 +1,12 @@ +[ + { + "applicationId": "iosdf;juasdfioj", + "bbox": null, + "id": "282d78f7ca1a2ec37bf3fcf3f24e7a27", + "speckle_type": "Objects.Geometry.Vector", + "units": "in", + "x": 321.321, + "y": 222.111, + "z": -1.001 + } +] \ No newline at end of file diff --git a/tests/Speckle.Objects.Tests.Unit/Serialization/ObjectsSerializationTest.cs b/tests/Speckle.Objects.Tests.Unit/Serialization/ObjectsSerializationTest.cs new file mode 100644 index 00000000..7df8e299 --- /dev/null +++ b/tests/Speckle.Objects.Tests.Unit/Serialization/ObjectsSerializationTest.cs @@ -0,0 +1,33 @@ +using Speckle.Sdk.Models; +using Speckle.Sdk.Serialisation; +using Speckle.Sdk.Serialisation.V2.Send; +using Speckle.Sdk.Testing; + +namespace Speckle.Objects.SerializationTests; + +public sealed class ObjectsSerializationTest +{ + [Theory] + [MemberData(nameof(ObjectsTestData.TheoryData), MemberType = typeof(ObjectsTestData))] + public async Task SerializeAndVerify(Base testCase) + { + var serialized = Serialize(testCase); + + await VerifySerialized(serialized).UseParameters(testCase); + } + + private static IReadOnlyList<(Id, Json, Dictionary)> Serialize(Base data) + { + using var serializer = new ObjectSerializerFactory(new BasePropertyGatherer()).Create( + new Dictionary(), + default + ); + return serializer.Serialize(data).ToList(); + } + + private static SettingsTask VerifySerialized(IReadOnlyList<(Id, Json, Dictionary)> serializedResult) + { + var jsons = serializedResult.OrderBy(x => x.Item1.Value).Select(x => x.Item2).ToArray(); + return SpeckleVerify.VerifyJsons(jsons); + } +} diff --git a/tests/Speckle.Objects.Tests.Unit/Serialization/ObjectsTestData.cs b/tests/Speckle.Objects.Tests.Unit/Serialization/ObjectsTestData.cs new file mode 100644 index 00000000..9365a3d9 --- /dev/null +++ b/tests/Speckle.Objects.Tests.Unit/Serialization/ObjectsTestData.cs @@ -0,0 +1,46 @@ +using Speckle.Objects.Geometry; +using Speckle.Sdk.Common; +using Speckle.Sdk.Models; +using Point = Speckle.Objects.Geometry.Point; + +namespace Speckle.Objects.SerializationTests; + +public static class ObjectsTestData +{ + /// + /// Data set of simple valid Speckle Objects + /// Right now, we should have exactly one for each non-abstract object model. + /// + /// + private static IEnumerable Data() + { + yield return new Mesh() + { + vertices = [0d, 0d, 0d, 1d, 0d, 0d, 1d, 1d, 0d], + faces = [3, 0, 1, 2], + applicationId = "asdfasdf", + units = Units.Meters, + area = 42, + volume = 420, + colors = [-10185235, -10185235, -10185235], + }; + yield return new Point() + { + x = 123.123, + y = 111.222, + z = -0.001, + applicationId = "iosdf;juasdfioj", + units = Units.Feet, + }; + yield return new Vector() + { + x = 321.321, + y = 222.111, + z = -1.001, + applicationId = "iosdf;juasdfioj", + units = Units.Inches, + }; + } + + public static TheoryData TheoryData => new(Data()); +} diff --git a/tests/Speckle.Objects.Tests.Unit/packages.lock.json b/tests/Speckle.Objects.Tests.Unit/packages.lock.json index 3eb30310..f86bb622 100644 --- a/tests/Speckle.Objects.Tests.Unit/packages.lock.json +++ b/tests/Speckle.Objects.Tests.Unit/packages.lock.json @@ -10,9 +10,9 @@ }, "AwesomeAssertions": { "type": "Direct", - "requested": "[8.0.0, )", - "resolved": "8.0.0", - "contentHash": "6fWiV7mGZUzZXzeiW3hWF0nJokuuNm4hnzuqbM3IXHqGYkWnHl65+wNpuQ73xfJXClX0fmfKcTdQ2Ula719IDg==" + "requested": "[8.1.0, )", + "resolved": "8.1.0", + "contentHash": "IfNC4cpXPi9tclWvuNO9lfkuIxJsUTLTS1NXto55jDrAUQJYl0zLI9ByISrfkbBE2Xtg+IWaAXQ6jnUx3anDuw==" }, "Microsoft.NET.Test.Sdk": { "type": "Direct", @@ -60,22 +60,30 @@ }, "Argon": { "type": "Transitive", - "resolved": "0.26.0", - "contentHash": "n7btGXdtRyprGnpLMpBs6rLScxlvPtVWwmTR8h7CtJvpZXBGhGvibEdZxRjeTZNrwf403jJ0ZPpt35Pz/NaNsw==" + "resolved": "0.27.0", + "contentHash": "LtZKATYeTwDyYq1AXrgVU/ly+nI6GvE0GK1isJYFPQOnb2uHUxvDA+yh40QYaITGTLViXK7rbWhNKpbZ5pb9XA==" + }, + "Castle.Core": { + "type": "Transitive", + "resolved": "5.1.1", + "contentHash": "rpYtIczkzGpf+EkZgDr9CClTdemhsrwA/W5hMoPjLkRFnXzH44zDLoovXeKtmxb1ykXK9aJVODSpiJml8CTw2g==", + "dependencies": { + "System.Diagnostics.EventLog": "6.0.0" + } }, "DiffEngine": { "type": "Transitive", - "resolved": "15.9.0", - "contentHash": "shE6+tO4w5BmQTX0z+WnUV4UfmPNn6oTqBINbkts6OP0Icyx5WROSDzjjb95EwVYC4IAS+PxxS4Vbapxz4hkdw==", + "resolved": "16.1.0", + "contentHash": "ImEFC6BN62paN0N7v8vrLY3x/LpfbJaJy5yDtL+/L2As6FI1npGJcFZwzz1A7pdDjIYPOXE91qv6BpgEUGjDkA==", "dependencies": { - "EmptyFiles": "8.7.1", - "System.Management": "9.0.1" + "EmptyFiles": "8.8.0", + "System.Management": "8.0.0" } }, "EmptyFiles": { "type": "Transitive", - "resolved": "8.7.1", - "contentHash": "C8pvg0TvG2Mkn5LGNFGkFgFu8SUgYFwiu8U3y34qGQnnwKmGnlQTfTIUrtzfSjPxA4q7L/kRu09U5p32otZ2Aw==" + "resolved": "8.8.0", + "contentHash": "d0pgc/vMyKgQ9T3qiiJBn1uYUSZ1/OShh6tySnNSkELRSgM4A4IOrpdQhLqwCkPwYvdJqzKuxQ6wn3MQAd4GNA==" }, "FSharp.Core": { "type": "Transitive", @@ -242,25 +250,30 @@ }, "System.CodeDom": { "type": "Transitive", - "resolved": "9.0.1", - "contentHash": "2J5uq+2smnj+u1jlyVJ6BGGqaK9fHcK/EwN7mbsuPqTI6dZr86br8Cg6o/5B+icQ9ANTvTDpJjnhDNtYYZijHQ==" + "resolved": "8.0.0", + "contentHash": "WTlRjL6KWIMr/pAaq3rYqh0TJlzpouaQ/W1eelssHgtlwHAH25jXTkUphTYx9HaIIf7XA6qs/0+YhtLEQRkJ+Q==" }, "System.ComponentModel.Annotations": { "type": "Transitive", "resolved": "4.5.0", "contentHash": "UxYQ3FGUOtzJ7LfSdnYSFd7+oEv6M8NgUatatIN2HxNtDdlcvFAf+VIq4Of9cDMJEJC0aSRv/x898RYhB4Yppg==" }, + "System.Diagnostics.EventLog": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "lcyUiXTsETK2ALsZrX+nWuHSIQeazhqPphLfaRxzdGaG93+0kELqpgEHtwWOlQe7+jSFnKwaCAgL4kjeZCQJnw==" + }, "System.IO.Hashing": { "type": "Transitive", - "resolved": "9.0.1", - "contentHash": "jY+E/PElNWQiazN0YHqZGvcSedcZ4Wt0Os1nnJ2SzR3gWZlhNRDkSXOhuHJcLuImD8SrJQQ8TfU0W4mVcit2hg==" + "resolved": "9.0.3", + "contentHash": "BrMGzDRLz410PE4qC8UeKeAc0hFRjBkiCUOLTwuod65NAjqg5tDNqYU7gP0A09taEXtecB+HJc1NNnnTjsKFAQ==" }, "System.Management": { "type": "Transitive", - "resolved": "9.0.1", - "contentHash": "CLEo9O6FuO4GQ3ZQkGssg9CJ2w2TN7GMFf3wHTc7YVWJV4xoyJRPw+XIDQnCcSUJCrHhrAWOO60cAX29EV5LFQ==", + "resolved": "8.0.0", + "contentHash": "jrK22i5LRzxZCfGb+tGmke2VH7oE0DvcDlJ1HAKYU8cPmD8XnpUT0bYn2Gy98GEhGjtfbR/sxKTVb+dE770pfA==", "dependencies": { - "System.CodeDom": "9.0.1" + "System.CodeDom": "8.0.0" } }, "System.Memory": { @@ -298,13 +311,13 @@ }, "Verify": { "type": "Transitive", - "resolved": "28.10.1", - "contentHash": "2B/VtFN5jtF5g28kaM4GdJZTwb3pisd4+wL2NEPi9ZYe2lghWsCzS30V6LF1ILApLBfAorAstkU/Vw3sDWRqrg==", + "resolved": "29.2.0", + "contentHash": "EhhwhXIeip9AJGWRPXh47NAUoiELnWzeBnAzFSl0+ryAfijTV1T+B4m6P6GbheWQ1CJ1cC1ZFLzgH276D5Bu3A==", "dependencies": { - "Argon": "0.26.0", - "DiffEngine": "15.9.0", + "Argon": "0.27.0", + "DiffEngine": "16.1.0", "SimpleInfoName": "3.1.0", - "System.IO.Hashing": "9.0.1" + "System.IO.Hashing": "9.0.3" } }, "xunit.abstractions": { @@ -312,6 +325,20 @@ "resolved": "2.0.3", "contentHash": "pot1I4YOxlWjIb5jmwvvQNbTrZ3lJQ+jUGkGjWE3hEFM0l5gOnBWS+H3qsex68s5cO52g+44vpGzhAt+42vwKg==" }, + "xunit.analyzers": { + "type": "Transitive", + "resolved": "1.18.0", + "contentHash": "OtFMHN8yqIcYP9wcVIgJrq01AfTxijjAqVDy/WeQVSyrDC1RzBWeQPztL49DN2syXRah8TYnfvk035s7L95EZQ==" + }, + "xunit.core": { + "type": "Transitive", + "resolved": "2.9.3", + "contentHash": "BiAEvqGvyme19wE0wTKdADH+NloYqikiU0mcnmiNyXaF9HyHmE6sr/3DC5vnBkgsWaE6yPyWszKSPSApWdRVeQ==", + "dependencies": { + "xunit.extensibility.core": "[2.9.3]", + "xunit.extensibility.execution": "[2.9.3]" + } + }, "xunit.extensibility.core": { "type": "Transitive", "resolved": "2.9.3", @@ -354,9 +381,11 @@ "type": "Project", "dependencies": { "Microsoft.NET.Test.Sdk": "[17.13.0, )", + "Moq": "[4.20.72, )", "Speckle.Sdk": "[1.0.0, )", "Verify.Quibble": "[2.1.1, )", - "Verify.Xunit": "[28.10.1, )", + "Verify.Xunit": "[29.2.0, )", + "xunit": "[2.9.3, )", "xunit.runner.visualstudio": "[3.0.2, )" } }, @@ -405,6 +434,15 @@ "Microsoft.Extensions.Options": "2.2.0" } }, + "Moq": { + "type": "CentralTransitive", + "requested": "[4.20.72, )", + "resolved": "4.20.72", + "contentHash": "EA55cjyNn8eTNWrgrdZJH5QLFp2L43oxl1tlkoYUKIE9pRwL784OWiTXeCV5ApS+AMYEAlt7Fo03A2XfouvHmQ==", + "dependencies": { + "Castle.Core": "5.1.1" + } + }, "Speckle.DoubleNumerics": { "type": "CentralTransitive", "requested": "[4.1.0, )", @@ -430,18 +468,29 @@ }, "Verify.Xunit": { "type": "CentralTransitive", - "requested": "[28.10.1, )", - "resolved": "28.10.1", - "contentHash": "mkG7agMlx8oAEGcHoRY72hyDyNTdLIrzbfmniXFQgQ3yKulAHSYvYc9quzhpg0Sy+jb3svbdLqnRSg0VRhet3A==", + "requested": "[29.2.0, )", + "resolved": "29.2.0", + "contentHash": "MdcslVf40AzSA319ZHMzR+U4JqyquX28JFSrI9zA89yeZNaNcaSIb5PmE0XZ6p60Iy7eRYtnGEgSDimEUeXHZw==", "dependencies": { - "Argon": "0.26.0", - "DiffEngine": "15.9.0", + "Argon": "0.27.0", + "DiffEngine": "16.1.0", "SimpleInfoName": "3.1.0", - "System.IO.Hashing": "9.0.1", - "Verify": "28.10.1", + "System.IO.Hashing": "9.0.3", + "Verify": "29.2.0", "xunit.abstractions": "2.0.3", "xunit.extensibility.execution": "2.9.3" } + }, + "xunit": { + "type": "CentralTransitive", + "requested": "[2.9.3, )", + "resolved": "2.9.3", + "contentHash": "TlXQBinK35LpOPKHAqbLY4xlEen9TBafjs0V5KnA4wZsoQLQJiirCR4CbIXvOH8NzkW4YeJKP5P/Bnrodm0h9Q==", + "dependencies": { + "xunit.analyzers": "1.18.0", + "xunit.assert": "2.9.3", + "xunit.core": "[2.9.3]" + } } } } diff --git a/tests/Speckle.Sdk.Serialization.Testing/Program.cs b/tests/Speckle.Sdk.Serialization.Testing/Program.cs index 51b285eb..a0f2d95d 100644 --- a/tests/Speckle.Sdk.Serialization.Testing/Program.cs +++ b/tests/Speckle.Sdk.Serialization.Testing/Program.cs @@ -1,22 +1,14 @@ #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; 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"; @@ -33,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"); @@ -41,21 +33,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 +49,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.Cancellation_Receive_Cache.verified.json b/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.Cancellation_Receive_Cache.verified.json index 94cd413d..cdc627d2 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.Cancellation_Receive_Cache.verified.json +++ b/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.Cancellation_Receive_Cache.verified.json @@ -1,5 +1,15 @@ { - "Type": "System.OperationCanceledException", + "CancellationToken": { + "IsCancellationRequested": true, + "CanBeCanceled": true, + "WaitHandle": { + "SafeWaitHandle": { + "IsClosed": false, + "IsInvalid": false + } + } + }, + "Data": {}, "Message": "The operation was canceled.", - "Source": "System.Private.CoreLib" + "Type": "OperationCanceledException" } diff --git a/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.Cancellation_Receive_Deserialize.verified.json b/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.Cancellation_Receive_Deserialize.verified.json index 94cd413d..cdc627d2 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.Cancellation_Receive_Deserialize.verified.json +++ b/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.Cancellation_Receive_Deserialize.verified.json @@ -1,5 +1,15 @@ { - "Type": "System.OperationCanceledException", + "CancellationToken": { + "IsCancellationRequested": true, + "CanBeCanceled": true, + "WaitHandle": { + "SafeWaitHandle": { + "IsClosed": false, + "IsInvalid": false + } + } + }, + "Data": {}, "Message": "The operation was canceled.", - "Source": "System.Private.CoreLib" + "Type": "OperationCanceledException" } diff --git a/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.Cancellation_Receive_Server.verified.json b/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.Cancellation_Receive_Server.verified.json index 94cd413d..cdc627d2 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.Cancellation_Receive_Server.verified.json +++ b/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.Cancellation_Receive_Server.verified.json @@ -1,5 +1,15 @@ { - "Type": "System.OperationCanceledException", + "CancellationToken": { + "IsCancellationRequested": true, + "CanBeCanceled": true, + "WaitHandle": { + "SafeWaitHandle": { + "IsClosed": false, + "IsInvalid": false + } + } + }, + "Data": {}, "Message": "The operation was canceled.", - "Source": "System.Private.CoreLib" + "Type": "OperationCanceledException" } diff --git a/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.Cancellation_Save_Server.verified.json b/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.Cancellation_Save_Server.verified.json index 94cd413d..cdc627d2 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.Cancellation_Save_Server.verified.json +++ b/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.Cancellation_Save_Server.verified.json @@ -1,5 +1,15 @@ { - "Type": "System.OperationCanceledException", + "CancellationToken": { + "IsCancellationRequested": true, + "CanBeCanceled": true, + "WaitHandle": { + "SafeWaitHandle": { + "IsClosed": false, + "IsInvalid": false + } + } + }, + "Data": {}, "Message": "The operation was canceled.", - "Source": "System.Private.CoreLib" + "Type": "OperationCanceledException" } diff --git a/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.Cancellation_Save_Sqlite.verified.json b/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.Cancellation_Save_Sqlite.verified.json index 94cd413d..cdc627d2 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.Cancellation_Save_Sqlite.verified.json +++ b/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.Cancellation_Save_Sqlite.verified.json @@ -1,5 +1,15 @@ { - "Type": "System.OperationCanceledException", + "CancellationToken": { + "IsCancellationRequested": true, + "CanBeCanceled": true, + "WaitHandle": { + "SafeWaitHandle": { + "IsClosed": false, + "IsInvalid": false + } + } + }, + "Data": {}, "Message": "The operation was canceled.", - "Source": "System.Private.CoreLib" + "Type": "OperationCanceledException" } diff --git a/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.Cancellation_Serialize.verified.json b/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.Cancellation_Serialize.verified.json index 94cd413d..cdc627d2 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.Cancellation_Serialize.verified.json +++ b/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.Cancellation_Serialize.verified.json @@ -1,5 +1,15 @@ { - "Type": "System.OperationCanceledException", + "CancellationToken": { + "IsCancellationRequested": true, + "CanBeCanceled": true, + "WaitHandle": { + "SafeWaitHandle": { + "IsClosed": false, + "IsInvalid": false + } + } + }, + "Data": {}, "Message": "The operation was canceled.", - "Source": "System.Private.CoreLib" + "Type": "OperationCanceledException" } diff --git a/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.cs b/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.cs index 5e2995a0..93e721d5 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/CancellationTests.cs @@ -1,10 +1,11 @@ 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 +15,15 @@ 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); + var serviceCollection = new ServiceCollection(); + serviceCollection.AddSpeckleSdk(new("Tests", "test"), "v3", typeof(TestClass).Assembly, typeof(Polyline).Assembly); + var serviceProvider = serviceCollection.BuildServiceProvider(); + + _factory = serviceProvider.GetRequiredService(); } [Fact] @@ -26,13 +32,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 +54,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 +75,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 +94,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 +121,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 +148,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..5bd3ef94 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs @@ -1,10 +1,9 @@ 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; using Speckle.Sdk.Models; using Speckle.Sdk.Serialisation; using Speckle.Sdk.Serialisation.V2; @@ -16,10 +15,15 @@ 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(new("Tests", "test"), "v3", typeof(TestClass).Assembly, typeof(Polyline).Assembly); + var serviceProvider = serviceCollection.BuildServiceProvider(); + + _factory = serviceProvider.GetRequiredService(); } [Fact] @@ -30,19 +34,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 +116,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 +183,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 +216,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.Test_Exceptions_Cache.verified.json b/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.Test_Exceptions_Cache.verified.json index a4c25449..08411c1d 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.Test_Exceptions_Cache.verified.json +++ b/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.Test_Exceptions_Cache.verified.json @@ -1,5 +1,11 @@ { - "Type": "Speckle.Sdk.SpeckleException", + "Data": {}, + "InnerException": { + "$type": "NotImplementedException", + "Data": {}, + "Message": "The method or operation is not implemented.", + "Type": "NotImplementedException" + }, "Message": "Error while sending", - "Source": "Speckle.Sdk" + "Type": "SpeckleException" } diff --git a/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.Test_Exceptions_Cache_ExceptionsAfter_10.verified.json b/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.Test_Exceptions_Cache_ExceptionsAfter_10.verified.json new file mode 100644 index 00000000..08411c1d --- /dev/null +++ b/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.Test_Exceptions_Cache_ExceptionsAfter_10.verified.json @@ -0,0 +1,11 @@ +{ + "Data": {}, + "InnerException": { + "$type": "NotImplementedException", + "Data": {}, + "Message": "The method or operation is not implemented.", + "Type": "NotImplementedException" + }, + "Message": "Error while sending", + "Type": "SpeckleException" +} diff --git a/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.Test_Exceptions_Receive_Cache_fileName=False.verified.json b/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.Test_Exceptions_Receive_Cache_fileName=False.verified.json index a4c25449..08411c1d 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.Test_Exceptions_Receive_Cache_fileName=False.verified.json +++ b/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.Test_Exceptions_Receive_Cache_fileName=False.verified.json @@ -1,5 +1,11 @@ { - "Type": "Speckle.Sdk.SpeckleException", + "Data": {}, + "InnerException": { + "$type": "NotImplementedException", + "Data": {}, + "Message": "The method or operation is not implemented.", + "Type": "NotImplementedException" + }, "Message": "Error while sending", - "Source": "Speckle.Sdk" + "Type": "SpeckleException" } diff --git a/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.Test_Exceptions_Receive_Cache_fileName=True.verified.json b/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.Test_Exceptions_Receive_Cache_fileName=True.verified.json index 1b778cf5..8a035026 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.Test_Exceptions_Receive_Cache_fileName=True.verified.json +++ b/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.Test_Exceptions_Receive_Cache_fileName=True.verified.json @@ -1,5 +1,5 @@ { - "Type": "System.NotImplementedException", + "Data": {}, "Message": "The method or operation is not implemented.", - "Source": "Speckle.Sdk.Serialization.Tests" + "Type": "NotImplementedException" } diff --git a/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.Test_Exceptions_Receive_Server.verified.json b/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.Test_Exceptions_Receive_Server.verified.json index 1b778cf5..8a035026 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.Test_Exceptions_Receive_Server.verified.json +++ b/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.Test_Exceptions_Receive_Server.verified.json @@ -1,5 +1,5 @@ { - "Type": "System.NotImplementedException", + "Data": {}, "Message": "The method or operation is not implemented.", - "Source": "Speckle.Sdk.Serialization.Tests" + "Type": "NotImplementedException" } diff --git a/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.Test_Exceptions_Receive_Server_Skip_Both.verified.json b/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.Test_Exceptions_Receive_Server_Skip_Both.verified.json index ec4502d8..d77dca7f 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.Test_Exceptions_Receive_Server_Skip_Both.verified.json +++ b/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.Test_Exceptions_Receive_Server_Skip_Both.verified.json @@ -1,5 +1,5 @@ { - "Type": "Speckle.Sdk.SpeckleException", + "Data": {}, "Message": "Cannot skip server and cache. Please choose one.", - "Source": "Speckle.Sdk" + "Type": "SpeckleException" } diff --git a/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.Test_Exceptions_Upload.verified.json b/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.Test_Exceptions_Upload.verified.json index a4c25449..08411c1d 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.Test_Exceptions_Upload.verified.json +++ b/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.Test_Exceptions_Upload.verified.json @@ -1,5 +1,11 @@ { - "Type": "Speckle.Sdk.SpeckleException", + "Data": {}, + "InnerException": { + "$type": "NotImplementedException", + "Data": {}, + "Message": "The method or operation is not implemented.", + "Type": "NotImplementedException" + }, "Message": "Error while sending", - "Source": "Speckle.Sdk" + "Type": "SpeckleException" } diff --git a/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.cs b/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.cs index a9315b8a..01ce4c64 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/ExceptionTests.cs @@ -1,8 +1,11 @@ +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; @@ -12,10 +15,15 @@ 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(new("Tests", "test"), "v3", typeof(TestClass).Assembly, typeof(Polyline).Assembly); + var serviceProvider = serviceCollection.BuildServiceProvider(); + + _factory = serviceProvider.GetRequiredService(); } [Fact] @@ -23,20 +31,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); } @@ -45,18 +51,32 @@ 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); + } + + [Fact] + public async Task Test_Exceptions_Cache_ExceptionsAfter_10() + { + var testClass = new TestClass() { RegularProperty = "Hello" }; + + await using var serializeProcess = _factory.CreateSerializeProcess( + new ExceptionSendCacheManager(exceptionsAfter: 10), + new MemoryServerObjectManager(new()), + null, + default, + new SerializeProcessOptions(false, false, false, true) + ); + + var ex = await Assert.ThrowsAsync(async () => await serializeProcess.Serialize(testClass)); await Verify(ex); } @@ -89,7 +109,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( @@ -114,7 +134,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( @@ -144,4 +164,23 @@ public class ExceptionTests } await Verify(ex).UseParameters(hasObject); } + + [SpeckleType("Objects.Geometry.BadBase")] + public class BadBase : Base + { +#pragma warning disable CA1065 + public string BadProp => throw new NotImplementedException(); +#pragma warning restore CA1065 + } + + [Fact] + public void Test_SpeckleSerializerException() + { + var factory = new ObjectSerializerFactory(new BasePropertyGatherer()); + var serializer = factory.Create(new Dictionary(), default); + Assert.Throws(() => + { + var _ = serializer.Serialize(new BadBase()).ToList(); + }); + } } diff --git a/tests/Speckle.Sdk.Serialization.Tests/ExplicitInterfaceTests.cs b/tests/Speckle.Sdk.Serialization.Tests/ExplicitInterfaceTests.cs index 0bd05a14..eddbd777 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/ExplicitInterfaceTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/ExplicitInterfaceTests.cs @@ -1,16 +1,23 @@ -using Microsoft.Extensions.Logging.Abstractions; -using Speckle.Sdk.Host; +using System.Collections.Concurrent; +using Microsoft.Extensions.DependencyInjection; 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(new("Tests", "test"), "v3", typeof(TestClass).Assembly); + var serviceProvider = serviceCollection.BuildServiceProvider(); + + _factory = serviceProvider.GetRequiredService(); } [Fact] @@ -18,19 +25,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/ExceptionSendCacheManager.cs b/tests/Speckle.Sdk.Serialization.Tests/Framework/ExceptionSendCacheManager.cs index 0534a477..7ac6a1df 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/Framework/ExceptionSendCacheManager.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/Framework/ExceptionSendCacheManager.cs @@ -2,21 +2,40 @@ namespace Speckle.Sdk.Serialization.Tests.Framework; -public class ExceptionSendCacheManager(bool? hasObject = null) : ISqLiteJsonCacheManager +public class ExceptionSendCacheManager(bool? hasObject = null, int? exceptionsAfter = null) : ISqLiteJsonCacheManager { + private int _count; + public void Dispose() { } public IReadOnlyCollection<(string Id, string Json)> GetAllObjects() => throw new NotImplementedException(); - public void DeleteObject(string id) => throw new NotImplementedException(); + public void DeleteObject(string id) => CheckExceptions(); public string? GetObject(string id) => null; - public void SaveObject(string id, string json) => throw new NotImplementedException(); + public void SaveObject(string id, string json) => CheckExceptions(); - public void UpdateObject(string id, string json) => throw new NotImplementedException(); + public void UpdateObject(string id, string json) => CheckExceptions(); - public void SaveObjects(IEnumerable<(string id, string json)> items) => throw new NotImplementedException(); + public void SaveObjects(IEnumerable<(string id, string json)> items) => CheckExceptions(); public bool HasObject(string objectId) => hasObject ?? throw new NotImplementedException(); + + private void CheckExceptions() + { + if (exceptionsAfter is not null) + { + if (exceptionsAfter.Value > _count) + { + _count++; + } + else + { + throw new Exception("Count exceeded"); + } + } + + throw new NotImplementedException(); + } } 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..7a2f2c62 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,17 @@ 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)); - } + var serviceCollection = new ServiceCollection(); + serviceCollection.AddSpeckleSdk(new("Tests", "test"), "v3", typeof(TestClass).Assembly, typeof(Polyline).Assembly); + var serviceProvider = serviceCollection.BuildServiceProvider(); - public string? LoadId(string id) => null; - - 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 +54,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 +94,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 +153,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 +187,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 +214,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/SerializationTypeTests.cs b/tests/Speckle.Sdk.Serialization.Tests/SerializationTypeTests.cs new file mode 100644 index 00000000..432e5103 --- /dev/null +++ b/tests/Speckle.Sdk.Serialization.Tests/SerializationTypeTests.cs @@ -0,0 +1,36 @@ +using FluentAssertions; +using Speckle.Sdk.Serialisation; +using Speckle.Sdk.Serialisation.V2.Send; + +namespace Speckle.Sdk.Serialization.Tests; + +public class SerializationTypeTests +{ + [Fact] + public void Json() + { + var json = new Json("{}"); + json.ToString().Should().Be("{}"); + } + + [Fact] + public void Id() + { + var id = new Id("id"); + id.ToString().Should().Be("id"); + id.Equals(new Id("id")).Should().BeTrue(); + id.Equals(new Id("id2")).Should().BeFalse(); + id.GetHashCode().Should().Be("id".GetHashCode()); + } + + [Fact] + public void BaseItem() + { + var id = new Id("id"); + var json = new Json("{}"); + var baseItem = new BaseItem(id, json, false, new Dictionary()); + baseItem.Equals(new BaseItem(id, json, false, new Dictionary())).Should().BeTrue(); + baseItem.Equals(new BaseItem(new Id("id2"), json, false, new Dictionary())).Should().BeFalse(); + baseItem.GetHashCode().Should().Be(id.GetHashCode()); + } +} diff --git a/tests/Speckle.Sdk.Serialization.Tests/ServerObjectManagerTests.DownloadObjects.verified.json b/tests/Speckle.Sdk.Serialization.Tests/ServerObjectManagerTests.DownloadObjects.verified.json new file mode 100644 index 00000000..488ea578 --- /dev/null +++ b/tests/Speckle.Sdk.Serialization.Tests/ServerObjectManagerTests.DownloadObjects.verified.json @@ -0,0 +1,10 @@ +{ + "6f422a35-6183-48b9-8021-d22ec97e8674": { + "id": "6f422a35-6183-48b9-8021-d22ec97e8674", + "value": true + }, + "ef2f7ea0-495a-46af-a9ad-f18a8a298597": { + "id": "ef2f7ea0-495a-46af-a9ad-f18a8a298597", + "value": true + } +} diff --git a/tests/Speckle.Sdk.Serialization.Tests/ServerObjectManagerTests.DownloadSingleObject.verified.json b/tests/Speckle.Sdk.Serialization.Tests/ServerObjectManagerTests.DownloadSingleObject.verified.json new file mode 100644 index 00000000..d9bb684e --- /dev/null +++ b/tests/Speckle.Sdk.Serialization.Tests/ServerObjectManagerTests.DownloadSingleObject.verified.json @@ -0,0 +1,4 @@ +{ + "id": "6f422a35-6183-48b9-8021-d22ec97e8674", + "value": true +} diff --git a/tests/Speckle.Sdk.Serialization.Tests/ServerObjectManagerTests.HasObjects.verified.json b/tests/Speckle.Sdk.Serialization.Tests/ServerObjectManagerTests.HasObjects.verified.json new file mode 100644 index 00000000..4295906d --- /dev/null +++ b/tests/Speckle.Sdk.Serialization.Tests/ServerObjectManagerTests.HasObjects.verified.json @@ -0,0 +1,4 @@ +{ + "6f422a35-6183-48b9-8021-d22ec97e8674": true, + "ef2f7ea0-495a-46af-a9ad-f18a8a298597": false +} diff --git a/tests/Speckle.Sdk.Serialization.Tests/ServerObjectManagerTests.cs b/tests/Speckle.Sdk.Serialization.Tests/ServerObjectManagerTests.cs new file mode 100644 index 00000000..5106d5b6 --- /dev/null +++ b/tests/Speckle.Sdk.Serialization.Tests/ServerObjectManagerTests.cs @@ -0,0 +1,216 @@ +using System.Net; +using System.Text; +using FluentAssertions; +using HttpMultipartParser; +using Moq; +using RichardSzalay.MockHttp; +using Speckle.Newtonsoft.Json; +using Speckle.Newtonsoft.Json.Linq; +using Speckle.Sdk.Common; +using Speckle.Sdk.Helpers; +using Speckle.Sdk.Logging; +using Speckle.Sdk.Serialisation; +using Speckle.Sdk.Serialisation.V2; +using Speckle.Sdk.Serialisation.V2.Send; +using Speckle.Sdk.Testing; + +namespace Speckle.Sdk.Serialization.Tests; + +public class ServerObjectManagerTests : MoqTest +{ + [Fact] + public async Task DownloadObjects() + { + var id = Guid.Parse("6f422a35-6183-48b9-8021-d22ec97e8674").ToString(); + var id2 = Guid.Parse("ef2f7ea0-495a-46af-a9ad-f18a8a298597").ToString(); + var ct = new CancellationToken(); + var token = "token"; + var timeout = 2; + var uri = new Uri("http://localhost"); + var streamId = "streamId"; + var jObject = new JObject { { "id", id }, { "value", true } }; + var jObject2 = new JObject { { "id", id2 }, { "value", true } }; + var mockHttp = new MockHttpMessageHandler(); + Dictionary postParameters = new() + { + { "objects", JsonConvert.SerializeObject(new List { id, id2 }) }, + }; + + string serializedPayload = JsonConvert.SerializeObject(postParameters); + mockHttp + .When(HttpMethod.Post, $"http://localhost/api/getobjects/{streamId}") + .WithContent(serializedPayload) + .Respond( + "application/json", + $"{id}\t{jObject.ToString(Formatting.None)}\n{id2}\t{jObject2.ToString(Formatting.None)}\n" + ); + var httpClient = mockHttp.ToHttpClient(); + var http = Create(); + http.Setup(x => x.CreateHttpClient(It.IsAny(), timeout, token)).Returns(httpClient); + + var activityFactory = Create(); + activityFactory.Setup(x => x.Start(null, "DownloadObjects")).Returns((ISdkActivity?)null); + + var serverObjectManager = new ServerObjectManager( + http.Object, + activityFactory.Object, + uri, + streamId, + token, + new(timeout: TimeSpan.FromSeconds(timeout)) + ); + var results = serverObjectManager.DownloadObjects(new List { id, id2 }, null, ct); + var objects = new JObject(); + await foreach (var (x, json) in results) + { + objects.Add(x, JToken.Parse(json)); + } + + await VerifyJson(objects.ToString(Formatting.Indented)); + } + + [Fact] + public async Task DownloadSingleObject() + { + var id = Guid.Parse("6f422a35-6183-48b9-8021-d22ec97e8674").ToString(); + var ct = new CancellationToken(); + var token = "token"; + var timeout = 2; + var uri = new Uri("http://localhost"); + var streamId = "streamId"; + var jObject = new JObject { { "id", id }, { "value", true } }; + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .When(HttpMethod.Get, $"http://localhost/objects/{streamId}/{id}/single") + .Respond("application/json", $"{jObject.ToString(Formatting.None)}\n"); + var httpClient = mockHttp.ToHttpClient(); + var http = Create(); + http.Setup(x => x.CreateHttpClient(It.IsAny(), timeout, token)).Returns(httpClient); + + var activityFactory = Create(); + activityFactory.Setup(x => x.Start(null, "DownloadSingleObject")).Returns((ISdkActivity?)null); + + var serverObjectManager = new ServerObjectManager( + http.Object, + activityFactory.Object, + uri, + streamId, + token, + new(timeout: TimeSpan.FromSeconds(timeout)) + ); + var json = await serverObjectManager.DownloadSingleObject(id, null, ct); + await VerifyJson(json); + } + + [Fact] + public async Task HasObjects() + { + var id = Guid.Parse("6f422a35-6183-48b9-8021-d22ec97e8674").ToString(); + var id2 = Guid.Parse("ef2f7ea0-495a-46af-a9ad-f18a8a298597").ToString(); + var ct = new CancellationToken(); + var token = "token"; + var timeout = 2; + var uri = new Uri("http://localhost"); + var streamId = "streamId"; + var mockHttp = new MockHttpMessageHandler(); + Dictionary postParameters = new() + { + { "objects", JsonConvert.SerializeObject(new List { id, id2 }) }, + }; + + Dictionary responseParameters = new() { { id, true }, { id2, false } }; + string serializedPayload = JsonConvert.SerializeObject(postParameters); + mockHttp + .When(HttpMethod.Post, $"http://localhost/api/diff/{streamId}") + .WithContent(serializedPayload) + .Respond("application/json", JsonConvert.SerializeObject(responseParameters)); + var httpClient = mockHttp.ToHttpClient(); + var http = Create(); + http.Setup(x => x.CreateHttpClient(It.IsAny(), timeout, token)).Returns(httpClient); + + var activityFactory = Create(); + activityFactory.Setup(x => x.Start(null, "HasObjects")).Returns((ISdkActivity?)null); + + var serverObjectManager = new ServerObjectManager( + http.Object, + activityFactory.Object, + uri, + streamId, + token, + new(timeout: TimeSpan.FromSeconds(timeout)) + ); + var results = await serverObjectManager.HasObjects(new List { id, id2 }, ct); + + await Verify(results); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task UploadObjects(bool compressed) + { + var id = Guid.Parse("6f422a35-6183-48b9-8021-d22ec97e8674").ToString(); + var id2 = Guid.Parse("ef2f7ea0-495a-46af-a9ad-f18a8a298597").ToString(); + var ct = new CancellationToken(); + var token = "token"; + var timeout = 2; + var uri = new Uri("http://localhost"); + var streamId = "streamId"; + var jObject = new JObject { { "id", id }, { "value", true } }; + var jObject2 = new JObject { { "id", id2 }, { "value", true } }; + + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .When(HttpMethod.Post, $"http://localhost/objects/{streamId}") + .Respond(x => HandleUploadRequest(x, compressed, new List { jObject, jObject2 })); + var httpClient = mockHttp.ToHttpClient(); + var http = Create(); + http.Setup(x => x.CreateHttpClient(It.IsAny(), timeout, token)).Returns(httpClient); + + var activityFactory = Create(); + activityFactory.Setup(x => x.Start(null, "UploadObjects")).Returns((ISdkActivity?)null); + + var serverObjectManager = new ServerObjectManager( + http.Object, + activityFactory.Object, + uri, + streamId, + token, + new(timeout: TimeSpan.FromSeconds(timeout), boundary: "boundary") + ); + await serverObjectManager.UploadObjects( + new List + { + new(new(id), new Json(jObject.ToString()), true, null), + new(new(id2), new Json(jObject2.ToString()), true, null), + }, + compressed, + null, + ct + ); + } + + private async Task HandleUploadRequest( + HttpRequestMessage req, + bool compressed, + List objects + ) + { + var content = await req.Content.NotNull().ReadAsStringAsync().ConfigureAwait(false); + var stream = new MemoryStream(Encoding.Default.GetBytes(content)); + var formData = await MultipartFormDataParser.ParseAsync(stream, "boundary"); + formData.Files.Count.Should().Be(1); + var file = formData.Files[0]; + file.FileName.Should().Be("batch-0"); + // file.ContentType.Should().Be("application/json"); + if (!compressed) + { + var dataStream = file.Data; + using var reader = new StreamReader(dataStream); + var s = await reader.ReadToEndAsync(); + JsonConvert.DeserializeObject>(s).Should().BeEquivalentTo(objects); + } + + return new HttpResponseMessage(HttpStatusCode.OK); + } +} 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 47352da9..bea3bd9b 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/Speckle.Sdk.Serialization.Tests.csproj +++ b/tests/Speckle.Sdk.Serialization.Tests/Speckle.Sdk.Serialization.Tests.csproj @@ -1,4 +1,4 @@ - + net8.0 @@ -9,7 +9,11 @@ + + + + diff --git a/tests/Speckle.Sdk.Serialization.Tests/packages.lock.json b/tests/Speckle.Sdk.Serialization.Tests/packages.lock.json index 3eb30310..517cd334 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/packages.lock.json +++ b/tests/Speckle.Sdk.Serialization.Tests/packages.lock.json @@ -10,9 +10,29 @@ }, "AwesomeAssertions": { "type": "Direct", - "requested": "[8.0.0, )", - "resolved": "8.0.0", - "contentHash": "6fWiV7mGZUzZXzeiW3hWF0nJokuuNm4hnzuqbM3IXHqGYkWnHl65+wNpuQ73xfJXClX0fmfKcTdQ2Ula719IDg==" + "requested": "[8.1.0, )", + "resolved": "8.1.0", + "contentHash": "IfNC4cpXPi9tclWvuNO9lfkuIxJsUTLTS1NXto55jDrAUQJYl0zLI9ByISrfkbBE2Xtg+IWaAXQ6jnUx3anDuw==" + }, + "HttpMultipartParser": { + "type": "Direct", + "requested": "[9.0.0, )", + "resolved": "9.0.0", + "contentHash": "WeGKDK62waagwo9nokRY62DrLukwVCNXOPVjrzi/qSS73D+B6zPOBkImsFqzhvRNweIobR74js9M2HTV+PTeIg==", + "dependencies": { + "Microsoft.CSharp": "4.7.0", + "Microsoft.IO.RecyclableMemoryStream": "3.0.1", + "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", @@ -34,12 +54,27 @@ "Microsoft.SourceLink.Common": "8.0.0" } }, + "Moq": { + "type": "Direct", + "requested": "[4.20.72, )", + "resolved": "4.20.72", + "contentHash": "EA55cjyNn8eTNWrgrdZJH5QLFp2L43oxl1tlkoYUKIE9pRwL784OWiTXeCV5ApS+AMYEAlt7Fo03A2XfouvHmQ==", + "dependencies": { + "Castle.Core": "5.1.1" + } + }, "PolySharp": { "type": "Direct", "requested": "[1.15.0, )", "resolved": "1.15.0", "contentHash": "FbU0El+EEjdpuIX4iDbeS7ki1uzpJPx8vbqOzEtqnl1GZeAGJfq+jCbxeJL2y0EPnUNk8dRnnqR2xnYXg9Tf+g==" }, + "RichardSzalay.MockHttp": { + "type": "Direct", + "requested": "[7.0.0, )", + "resolved": "7.0.0", + "contentHash": "QwnauYiaywp65QKFnP+wvgiQ2D8Pv888qB2dyfd7MSVDF06sIvxqASenk+RxsWybyyt+Hu1Y251wQxpHTv3UYg==" + }, "Speckle.InterfaceGenerator": { "type": "Direct", "requested": "[0.9.6, )", @@ -60,22 +95,30 @@ }, "Argon": { "type": "Transitive", - "resolved": "0.26.0", - "contentHash": "n7btGXdtRyprGnpLMpBs6rLScxlvPtVWwmTR8h7CtJvpZXBGhGvibEdZxRjeTZNrwf403jJ0ZPpt35Pz/NaNsw==" + "resolved": "0.27.0", + "contentHash": "LtZKATYeTwDyYq1AXrgVU/ly+nI6GvE0GK1isJYFPQOnb2uHUxvDA+yh40QYaITGTLViXK7rbWhNKpbZ5pb9XA==" + }, + "Castle.Core": { + "type": "Transitive", + "resolved": "5.1.1", + "contentHash": "rpYtIczkzGpf+EkZgDr9CClTdemhsrwA/W5hMoPjLkRFnXzH44zDLoovXeKtmxb1ykXK9aJVODSpiJml8CTw2g==", + "dependencies": { + "System.Diagnostics.EventLog": "6.0.0" + } }, "DiffEngine": { "type": "Transitive", - "resolved": "15.9.0", - "contentHash": "shE6+tO4w5BmQTX0z+WnUV4UfmPNn6oTqBINbkts6OP0Icyx5WROSDzjjb95EwVYC4IAS+PxxS4Vbapxz4hkdw==", + "resolved": "16.1.0", + "contentHash": "ImEFC6BN62paN0N7v8vrLY3x/LpfbJaJy5yDtL+/L2As6FI1npGJcFZwzz1A7pdDjIYPOXE91qv6BpgEUGjDkA==", "dependencies": { - "EmptyFiles": "8.7.1", - "System.Management": "9.0.1" + "EmptyFiles": "8.8.0", + "System.Management": "8.0.0" } }, "EmptyFiles": { "type": "Transitive", - "resolved": "8.7.1", - "contentHash": "C8pvg0TvG2Mkn5LGNFGkFgFu8SUgYFwiu8U3y34qGQnnwKmGnlQTfTIUrtzfSjPxA4q7L/kRu09U5p32otZ2Aw==" + "resolved": "8.8.0", + "contentHash": "d0pgc/vMyKgQ9T3qiiJBn1uYUSZ1/OShh6tySnNSkELRSgM4A4IOrpdQhLqwCkPwYvdJqzKuxQ6wn3MQAd4GNA==" }, "FSharp.Core": { "type": "Transitive", @@ -169,6 +212,11 @@ "System.Runtime.CompilerServices.Unsafe": "4.5.1" } }, + "Microsoft.IO.RecyclableMemoryStream": { + "type": "Transitive", + "resolved": "3.0.1", + "contentHash": "s/s20YTVY9r9TPfTrN5g8zPF1YhwxyqO6PxUkrYTGI2B+OGPe9AdajWZrLhFqXIvqIW23fnUE4+ztrUWNU1+9g==" + }, "Microsoft.SourceLink.Common": { "type": "Transitive", "resolved": "8.0.0", @@ -240,27 +288,37 @@ "SQLitePCLRaw.core": "2.1.4" } }, + "System.Buffers": { + "type": "Transitive", + "resolved": "4.6.0", + "contentHash": "lN6tZi7Q46zFzAbRYXTIvfXcyvQQgxnY7Xm6C6xQ9784dEL1amjM6S6Iw4ZpsvesAKnRVsM4scrDQaDqSClkjA==" + }, "System.CodeDom": { "type": "Transitive", - "resolved": "9.0.1", - "contentHash": "2J5uq+2smnj+u1jlyVJ6BGGqaK9fHcK/EwN7mbsuPqTI6dZr86br8Cg6o/5B+icQ9ANTvTDpJjnhDNtYYZijHQ==" + "resolved": "8.0.0", + "contentHash": "WTlRjL6KWIMr/pAaq3rYqh0TJlzpouaQ/W1eelssHgtlwHAH25jXTkUphTYx9HaIIf7XA6qs/0+YhtLEQRkJ+Q==" }, "System.ComponentModel.Annotations": { "type": "Transitive", "resolved": "4.5.0", "contentHash": "UxYQ3FGUOtzJ7LfSdnYSFd7+oEv6M8NgUatatIN2HxNtDdlcvFAf+VIq4Of9cDMJEJC0aSRv/x898RYhB4Yppg==" }, + "System.Diagnostics.EventLog": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "lcyUiXTsETK2ALsZrX+nWuHSIQeazhqPphLfaRxzdGaG93+0kELqpgEHtwWOlQe7+jSFnKwaCAgL4kjeZCQJnw==" + }, "System.IO.Hashing": { "type": "Transitive", - "resolved": "9.0.1", - "contentHash": "jY+E/PElNWQiazN0YHqZGvcSedcZ4Wt0Os1nnJ2SzR3gWZlhNRDkSXOhuHJcLuImD8SrJQQ8TfU0W4mVcit2hg==" + "resolved": "9.0.3", + "contentHash": "BrMGzDRLz410PE4qC8UeKeAc0hFRjBkiCUOLTwuod65NAjqg5tDNqYU7gP0A09taEXtecB+HJc1NNnnTjsKFAQ==" }, "System.Management": { "type": "Transitive", - "resolved": "9.0.1", - "contentHash": "CLEo9O6FuO4GQ3ZQkGssg9CJ2w2TN7GMFf3wHTc7YVWJV4xoyJRPw+XIDQnCcSUJCrHhrAWOO60cAX29EV5LFQ==", + "resolved": "8.0.0", + "contentHash": "jrK22i5LRzxZCfGb+tGmke2VH7oE0DvcDlJ1HAKYU8cPmD8XnpUT0bYn2Gy98GEhGjtfbR/sxKTVb+dE770pfA==", "dependencies": { - "System.CodeDom": "9.0.1" + "System.CodeDom": "8.0.0" } }, "System.Memory": { @@ -298,13 +356,13 @@ }, "Verify": { "type": "Transitive", - "resolved": "28.10.1", - "contentHash": "2B/VtFN5jtF5g28kaM4GdJZTwb3pisd4+wL2NEPi9ZYe2lghWsCzS30V6LF1ILApLBfAorAstkU/Vw3sDWRqrg==", + "resolved": "29.2.0", + "contentHash": "EhhwhXIeip9AJGWRPXh47NAUoiELnWzeBnAzFSl0+ryAfijTV1T+B4m6P6GbheWQ1CJ1cC1ZFLzgH276D5Bu3A==", "dependencies": { - "Argon": "0.26.0", - "DiffEngine": "15.9.0", + "Argon": "0.27.0", + "DiffEngine": "16.1.0", "SimpleInfoName": "3.1.0", - "System.IO.Hashing": "9.0.1" + "System.IO.Hashing": "9.0.3" } }, "xunit.abstractions": { @@ -312,6 +370,20 @@ "resolved": "2.0.3", "contentHash": "pot1I4YOxlWjIb5jmwvvQNbTrZ3lJQ+jUGkGjWE3hEFM0l5gOnBWS+H3qsex68s5cO52g+44vpGzhAt+42vwKg==" }, + "xunit.analyzers": { + "type": "Transitive", + "resolved": "1.18.0", + "contentHash": "OtFMHN8yqIcYP9wcVIgJrq01AfTxijjAqVDy/WeQVSyrDC1RzBWeQPztL49DN2syXRah8TYnfvk035s7L95EZQ==" + }, + "xunit.core": { + "type": "Transitive", + "resolved": "2.9.3", + "contentHash": "BiAEvqGvyme19wE0wTKdADH+NloYqikiU0mcnmiNyXaF9HyHmE6sr/3DC5vnBkgsWaE6yPyWszKSPSApWdRVeQ==", + "dependencies": { + "xunit.extensibility.core": "[2.9.3]", + "xunit.extensibility.execution": "[2.9.3]" + } + }, "xunit.extensibility.core": { "type": "Transitive", "resolved": "2.9.3", @@ -354,9 +426,11 @@ "type": "Project", "dependencies": { "Microsoft.NET.Test.Sdk": "[17.13.0, )", + "Moq": "[4.20.72, )", "Speckle.Sdk": "[1.0.0, )", "Verify.Quibble": "[2.1.1, )", - "Verify.Xunit": "[28.10.1, )", + "Verify.Xunit": "[29.2.0, )", + "xunit": "[2.9.3, )", "xunit.runner.visualstudio": "[3.0.2, )" } }, @@ -430,18 +504,29 @@ }, "Verify.Xunit": { "type": "CentralTransitive", - "requested": "[28.10.1, )", - "resolved": "28.10.1", - "contentHash": "mkG7agMlx8oAEGcHoRY72hyDyNTdLIrzbfmniXFQgQ3yKulAHSYvYc9quzhpg0Sy+jb3svbdLqnRSg0VRhet3A==", + "requested": "[29.2.0, )", + "resolved": "29.2.0", + "contentHash": "MdcslVf40AzSA319ZHMzR+U4JqyquX28JFSrI9zA89yeZNaNcaSIb5PmE0XZ6p60Iy7eRYtnGEgSDimEUeXHZw==", "dependencies": { - "Argon": "0.26.0", - "DiffEngine": "15.9.0", + "Argon": "0.27.0", + "DiffEngine": "16.1.0", "SimpleInfoName": "3.1.0", - "System.IO.Hashing": "9.0.1", - "Verify": "28.10.1", + "System.IO.Hashing": "9.0.3", + "Verify": "29.2.0", "xunit.abstractions": "2.0.3", "xunit.extensibility.execution": "2.9.3" } + }, + "xunit": { + "type": "CentralTransitive", + "requested": "[2.9.3, )", + "resolved": "2.9.3", + "contentHash": "TlXQBinK35LpOPKHAqbLY4xlEen9TBafjs0V5KnA4wZsoQLQJiirCR4CbIXvOH8NzkW4YeJKP5P/Bnrodm0h9Q==", + "dependencies": { + "xunit.analyzers": "1.18.0", + "xunit.assert": "2.9.3", + "xunit.core": "[2.9.3]" + } } } } diff --git a/tests/Speckle.Sdk.Testing/Framework/AggregationExceptionScrubber.cs b/tests/Speckle.Sdk.Testing/Framework/AggregationExceptionScrubber.cs deleted file mode 100644 index 2c96cfce..00000000 --- a/tests/Speckle.Sdk.Testing/Framework/AggregationExceptionScrubber.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Speckle.Sdk.Common; - -namespace Speckle.Sdk.Testing.Framework; - -public class AggregationExceptionScrubber : WriteOnlyJsonConverter -{ - private static readonly ExceptionScrubber _innerScrubber = new(); - - public override void Write(VerifyJsonWriter writer, AggregateException exception) - { - writer.WriteStartObject(); - - writer.WriteMember(exception, exception.GetType().FullName, "Type"); - if (exception.InnerExceptions.Count == 1) - { - writer.WritePropertyName("InnerException"); - _innerScrubber.Write(writer, exception.InnerException.NotNull()); - } - else - { - writer.WritePropertyName("InnerExceptions"); - writer.WriteStartArray(); - foreach (var innerException in exception.InnerExceptions) - { - _innerScrubber.Write(writer, innerException); - } - writer.WriteEndArray(); - } - - writer.WriteEndObject(); - } -} diff --git a/tests/Speckle.Sdk.Testing/Framework/DummyReceiveServerObjectManager.cs b/tests/Speckle.Sdk.Testing/Framework/DummyReceiveServerObjectManager.cs index 75787dc7..e038f33c 100644 --- a/tests/Speckle.Sdk.Testing/Framework/DummyReceiveServerObjectManager.cs +++ b/tests/Speckle.Sdk.Testing/Framework/DummyReceiveServerObjectManager.cs @@ -37,14 +37,14 @@ public class DummyReceiveServerObjectManager(IReadOnlyDictionary ) => throw new NotImplementedException(); public Task UploadObjects( - IReadOnlyList objects, + IReadOnlyList objectsToUpload, bool compressPayloads, IProgress? progress, CancellationToken cancellationToken ) { long totalBytes = 0; - foreach (var item in objects) + foreach (var item in objectsToUpload) { totalBytes += Encoding.Default.GetByteCount(item.Json.Value); } diff --git a/tests/Speckle.Sdk.Testing/Framework/DummySendServerObjectManager.cs b/tests/Speckle.Sdk.Testing/Framework/DummySendServerObjectManager.cs index 0ae163c4..ca46a915 100644 --- a/tests/Speckle.Sdk.Testing/Framework/DummySendServerObjectManager.cs +++ b/tests/Speckle.Sdk.Testing/Framework/DummySendServerObjectManager.cs @@ -22,10 +22,7 @@ public class DummySendServerObjectManager(ConcurrentDictionary s public Task> HasObjects( IReadOnlyCollection objectIds, CancellationToken cancellationToken - ) - { - return Task.FromResult(objectIds.Distinct().ToDictionary(x => x, savedObjects.ContainsKey)); - } + ) => Task.FromResult(objectIds.Distinct().ToDictionary(x => x, _ => false)); public Task UploadObjects( IReadOnlyList objects, diff --git a/tests/Speckle.Sdk.Testing/Framework/ExceptionScrubber.cs b/tests/Speckle.Sdk.Testing/Framework/ExceptionScrubber.cs deleted file mode 100644 index 3209a6bb..00000000 --- a/tests/Speckle.Sdk.Testing/Framework/ExceptionScrubber.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Argon; - -namespace Speckle.Sdk.Testing.Framework; - -public class ExceptionScrubber : WriteOnlyJsonConverter -{ - public override void Write(VerifyJsonWriter writer, Exception value) - { - var ex = new JObject - { - ["Type"] = value.GetType().FullName, - ["Message"] = value.Message, - ["Source"] = value.Source?.Trim(), - }; - //intentionally removed stacktrace to avoid errors on different machines and line numbers - writer.WriteRawValue(ex.ToString(Formatting.Indented)); - } -} diff --git a/tests/Speckle.Sdk.Testing/Framework/IdStringSerializer.cs b/tests/Speckle.Sdk.Testing/Framework/IdStringSerializer.cs deleted file mode 100644 index 5a7e7258..00000000 --- a/tests/Speckle.Sdk.Testing/Framework/IdStringSerializer.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using Argon; -using Speckle.Sdk.Common; -using Speckle.Sdk.Serialisation; - -namespace Speckle.Sdk.Testing.Framework; - -[SuppressMessage("Design", "CA1062:Validate arguments of public methods")] -public class IdStringSerializer : JsonConverter -{ - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - var id = (Id)value; - writer.WriteValue(id.Value); - } - - public override object? ReadJson(JsonReader reader, Type type, object? existingValue, JsonSerializer serializer) - { - var json = reader.ReadAsString(); - return new Id(json.NotNull()); - } - - public override bool CanConvert(Type type) => typeof(Id) == type; -} diff --git a/tests/Speckle.Sdk.Testing/MoqTest.cs b/tests/Speckle.Sdk.Testing/MoqTest.cs new file mode 100644 index 00000000..34e8391b --- /dev/null +++ b/tests/Speckle.Sdk.Testing/MoqTest.cs @@ -0,0 +1,17 @@ +using System.Diagnostics.CodeAnalysis; +using Moq; + +namespace Speckle.Sdk.Testing; + +[ExcludeFromCodeCoverage] +public abstract class MoqTest : IDisposable +{ + protected MoqTest() => Repository = new(MockBehavior.Strict); + + public void Dispose() => Repository.VerifyAll(); + + protected MockRepository Repository { get; private set; } = new(MockBehavior.Strict); + + protected Mock Create(MockBehavior behavior = MockBehavior.Strict) + where T : class => Repository.Create(behavior); +} diff --git a/tests/Speckle.Sdk.Testing/Speckle.Sdk.Testing.csproj b/tests/Speckle.Sdk.Testing/Speckle.Sdk.Testing.csproj index b5ecb4ed..2238b7c0 100644 --- a/tests/Speckle.Sdk.Testing/Speckle.Sdk.Testing.csproj +++ b/tests/Speckle.Sdk.Testing/Speckle.Sdk.Testing.csproj @@ -7,8 +7,10 @@ + + diff --git a/tests/Speckle.Sdk.Testing/SpeckleVerify.cs b/tests/Speckle.Sdk.Testing/SpeckleVerify.cs index 4cb3946f..1b076af9 100644 --- a/tests/Speckle.Sdk.Testing/SpeckleVerify.cs +++ b/tests/Speckle.Sdk.Testing/SpeckleVerify.cs @@ -25,13 +25,7 @@ public static class SpeckleVerify VerifierSettings.DontIgnoreEmptyCollections(); VerifierSettings.SortPropertiesAlphabetically(); VerifierSettings.SortJsonObjects(); - VerifierSettings.AddExtraSettings(x => - { - var existing = x.Converters.OfType>().First(); - x.Converters.Remove(existing); - x.Converters.Add(new AggregationExceptionScrubber()); - x.Converters.Add(new ExceptionScrubber()); - }); + VerifierSettings.IgnoreStackTrace(); VerifyQuibble.Initialize(); } @@ -42,16 +36,19 @@ public static class SpeckleVerify Converters = { new JsonStringSerializer() }, }; - private static async Task VerifyJsonObjects(IDictionary objects, string sourceFile) => - await VerifyJson(JObject.FromObject(objects, _jsonSerializer).ToString(), sourceFile: sourceFile); + private static SettingsTask VerifyJsonObjects(IDictionary objects, string sourceFile) => + VerifyJson(JObject.FromObject(objects, _jsonSerializer).ToString(), sourceFile: sourceFile); - public static async Task VerifyJsonDictionary( + public static SettingsTask VerifyJsonDictionary( IDictionary objects, [CallerFilePath] string sourceFile = "" - ) => await VerifyJsonObjects(objects.ToDictionary(x => x.Key, x => new Json(x.Value)), sourceFile); + ) => VerifyJsonObjects(objects.ToDictionary(x => x.Key, x => new Json(x.Value)), sourceFile); - public static async Task VerifyJsonDictionary( + public static SettingsTask VerifyJsonDictionary( IDictionary objects, [CallerFilePath] string sourceFile = "" - ) => await VerifyJsonObjects(objects.ToDictionary(x => x.Key.Value, x => x.Value), sourceFile); + ) => VerifyJsonObjects(objects.ToDictionary(x => x.Key.Value, x => x.Value), sourceFile); + + public static SettingsTask VerifyJsons(IReadOnlyCollection objects, [CallerFilePath] string sourceFile = "") => + VerifyJson(JArray.FromObject(objects, _jsonSerializer).ToString(), sourceFile: sourceFile); } diff --git a/tests/Speckle.Sdk.Testing/packages.lock.json b/tests/Speckle.Sdk.Testing/packages.lock.json index 64fa5df7..0b4d76b5 100644 --- a/tests/Speckle.Sdk.Testing/packages.lock.json +++ b/tests/Speckle.Sdk.Testing/packages.lock.json @@ -22,6 +22,15 @@ "Microsoft.SourceLink.Common": "8.0.0" } }, + "Moq": { + "type": "Direct", + "requested": "[4.20.72, )", + "resolved": "4.20.72", + "contentHash": "EA55cjyNn8eTNWrgrdZJH5QLFp2L43oxl1tlkoYUKIE9pRwL784OWiTXeCV5ApS+AMYEAlt7Fo03A2XfouvHmQ==", + "dependencies": { + "Castle.Core": "5.1.1" + } + }, "PolySharp": { "type": "Direct", "requested": "[1.15.0, )", @@ -47,19 +56,30 @@ }, "Verify.Xunit": { "type": "Direct", - "requested": "[28.10.1, )", - "resolved": "28.10.1", - "contentHash": "mkG7agMlx8oAEGcHoRY72hyDyNTdLIrzbfmniXFQgQ3yKulAHSYvYc9quzhpg0Sy+jb3svbdLqnRSg0VRhet3A==", + "requested": "[29.2.0, )", + "resolved": "29.2.0", + "contentHash": "MdcslVf40AzSA319ZHMzR+U4JqyquX28JFSrI9zA89yeZNaNcaSIb5PmE0XZ6p60Iy7eRYtnGEgSDimEUeXHZw==", "dependencies": { - "Argon": "0.26.0", - "DiffEngine": "15.9.0", + "Argon": "0.27.0", + "DiffEngine": "16.1.0", "SimpleInfoName": "3.1.0", - "System.IO.Hashing": "9.0.1", - "Verify": "28.10.1", + "System.IO.Hashing": "9.0.3", + "Verify": "29.2.0", "xunit.abstractions": "2.0.3", "xunit.extensibility.execution": "2.9.3" } }, + "xunit": { + "type": "Direct", + "requested": "[2.9.3, )", + "resolved": "2.9.3", + "contentHash": "TlXQBinK35LpOPKHAqbLY4xlEen9TBafjs0V5KnA4wZsoQLQJiirCR4CbIXvOH8NzkW4YeJKP5P/Bnrodm0h9Q==", + "dependencies": { + "xunit.analyzers": "1.18.0", + "xunit.assert": "2.9.3", + "xunit.core": "[2.9.3]" + } + }, "xunit.runner.visualstudio": { "type": "Direct", "requested": "[3.0.2, )", @@ -68,22 +88,30 @@ }, "Argon": { "type": "Transitive", - "resolved": "0.26.0", - "contentHash": "n7btGXdtRyprGnpLMpBs6rLScxlvPtVWwmTR8h7CtJvpZXBGhGvibEdZxRjeTZNrwf403jJ0ZPpt35Pz/NaNsw==" + "resolved": "0.27.0", + "contentHash": "LtZKATYeTwDyYq1AXrgVU/ly+nI6GvE0GK1isJYFPQOnb2uHUxvDA+yh40QYaITGTLViXK7rbWhNKpbZ5pb9XA==" + }, + "Castle.Core": { + "type": "Transitive", + "resolved": "5.1.1", + "contentHash": "rpYtIczkzGpf+EkZgDr9CClTdemhsrwA/W5hMoPjLkRFnXzH44zDLoovXeKtmxb1ykXK9aJVODSpiJml8CTw2g==", + "dependencies": { + "System.Diagnostics.EventLog": "6.0.0" + } }, "DiffEngine": { "type": "Transitive", - "resolved": "15.9.0", - "contentHash": "shE6+tO4w5BmQTX0z+WnUV4UfmPNn6oTqBINbkts6OP0Icyx5WROSDzjjb95EwVYC4IAS+PxxS4Vbapxz4hkdw==", + "resolved": "16.1.0", + "contentHash": "ImEFC6BN62paN0N7v8vrLY3x/LpfbJaJy5yDtL+/L2As6FI1npGJcFZwzz1A7pdDjIYPOXE91qv6BpgEUGjDkA==", "dependencies": { - "EmptyFiles": "8.7.1", - "System.Management": "9.0.1" + "EmptyFiles": "8.8.0", + "System.Management": "8.0.0" } }, "EmptyFiles": { "type": "Transitive", - "resolved": "8.7.1", - "contentHash": "C8pvg0TvG2Mkn5LGNFGkFgFu8SUgYFwiu8U3y34qGQnnwKmGnlQTfTIUrtzfSjPxA4q7L/kRu09U5p32otZ2Aw==" + "resolved": "8.8.0", + "contentHash": "d0pgc/vMyKgQ9T3qiiJBn1uYUSZ1/OShh6tySnNSkELRSgM4A4IOrpdQhLqwCkPwYvdJqzKuxQ6wn3MQAd4GNA==" }, "FSharp.Core": { "type": "Transitive", @@ -250,25 +278,30 @@ }, "System.CodeDom": { "type": "Transitive", - "resolved": "9.0.1", - "contentHash": "2J5uq+2smnj+u1jlyVJ6BGGqaK9fHcK/EwN7mbsuPqTI6dZr86br8Cg6o/5B+icQ9ANTvTDpJjnhDNtYYZijHQ==" + "resolved": "8.0.0", + "contentHash": "WTlRjL6KWIMr/pAaq3rYqh0TJlzpouaQ/W1eelssHgtlwHAH25jXTkUphTYx9HaIIf7XA6qs/0+YhtLEQRkJ+Q==" }, "System.ComponentModel.Annotations": { "type": "Transitive", "resolved": "4.5.0", "contentHash": "UxYQ3FGUOtzJ7LfSdnYSFd7+oEv6M8NgUatatIN2HxNtDdlcvFAf+VIq4Of9cDMJEJC0aSRv/x898RYhB4Yppg==" }, + "System.Diagnostics.EventLog": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "lcyUiXTsETK2ALsZrX+nWuHSIQeazhqPphLfaRxzdGaG93+0kELqpgEHtwWOlQe7+jSFnKwaCAgL4kjeZCQJnw==" + }, "System.IO.Hashing": { "type": "Transitive", - "resolved": "9.0.1", - "contentHash": "jY+E/PElNWQiazN0YHqZGvcSedcZ4Wt0Os1nnJ2SzR3gWZlhNRDkSXOhuHJcLuImD8SrJQQ8TfU0W4mVcit2hg==" + "resolved": "9.0.3", + "contentHash": "BrMGzDRLz410PE4qC8UeKeAc0hFRjBkiCUOLTwuod65NAjqg5tDNqYU7gP0A09taEXtecB+HJc1NNnnTjsKFAQ==" }, "System.Management": { "type": "Transitive", - "resolved": "9.0.1", - "contentHash": "CLEo9O6FuO4GQ3ZQkGssg9CJ2w2TN7GMFf3wHTc7YVWJV4xoyJRPw+XIDQnCcSUJCrHhrAWOO60cAX29EV5LFQ==", + "resolved": "8.0.0", + "contentHash": "jrK22i5LRzxZCfGb+tGmke2VH7oE0DvcDlJ1HAKYU8cPmD8XnpUT0bYn2Gy98GEhGjtfbR/sxKTVb+dE770pfA==", "dependencies": { - "System.CodeDom": "9.0.1" + "System.CodeDom": "8.0.0" } }, "System.Memory": { @@ -306,13 +339,13 @@ }, "Verify": { "type": "Transitive", - "resolved": "28.10.1", - "contentHash": "2B/VtFN5jtF5g28kaM4GdJZTwb3pisd4+wL2NEPi9ZYe2lghWsCzS30V6LF1ILApLBfAorAstkU/Vw3sDWRqrg==", + "resolved": "29.2.0", + "contentHash": "EhhwhXIeip9AJGWRPXh47NAUoiELnWzeBnAzFSl0+ryAfijTV1T+B4m6P6GbheWQ1CJ1cC1ZFLzgH276D5Bu3A==", "dependencies": { - "Argon": "0.26.0", - "DiffEngine": "15.9.0", + "Argon": "0.27.0", + "DiffEngine": "16.1.0", "SimpleInfoName": "3.1.0", - "System.IO.Hashing": "9.0.1" + "System.IO.Hashing": "9.0.3" } }, "xunit.abstractions": { @@ -320,6 +353,20 @@ "resolved": "2.0.3", "contentHash": "pot1I4YOxlWjIb5jmwvvQNbTrZ3lJQ+jUGkGjWE3hEFM0l5gOnBWS+H3qsex68s5cO52g+44vpGzhAt+42vwKg==" }, + "xunit.analyzers": { + "type": "Transitive", + "resolved": "1.18.0", + "contentHash": "OtFMHN8yqIcYP9wcVIgJrq01AfTxijjAqVDy/WeQVSyrDC1RzBWeQPztL49DN2syXRah8TYnfvk035s7L95EZQ==" + }, + "xunit.core": { + "type": "Transitive", + "resolved": "2.9.3", + "contentHash": "BiAEvqGvyme19wE0wTKdADH+NloYqikiU0mcnmiNyXaF9HyHmE6sr/3DC5vnBkgsWaE6yPyWszKSPSApWdRVeQ==", + "dependencies": { + "xunit.extensibility.core": "[2.9.3]", + "xunit.extensibility.execution": "[2.9.3]" + } + }, "xunit.extensibility.core": { "type": "Transitive", "resolved": "2.9.3", @@ -408,6 +455,12 @@ "requested": "[13.0.2, )", "resolved": "13.0.2", "contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA==" + }, + "xunit.assert": { + "type": "CentralTransitive", + "requested": "[2.9.3, )", + "resolved": "2.9.3", + "contentHash": "/Kq28fCE7MjOV42YLVRAJzRF0WmEqsmflm0cfpMjGtzQ2lR5mYVj1/i0Y8uDAOLczkL3/jArrwehfMD0YogMAA==" } } } diff --git a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/GraphQLClientExceptionHandling.cs b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/GraphQLClientExceptionHandling.cs index 4f81fd93..b72b5977 100644 --- a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/GraphQLClientExceptionHandling.cs +++ b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/GraphQLClientExceptionHandling.cs @@ -5,13 +5,12 @@ using GraphQL.Client.Http; using Speckle.Newtonsoft.Json; using Speckle.Sdk.Api; using Speckle.Sdk.Api.GraphQL.Inputs; -using Xunit; namespace Speckle.Sdk.Tests.Integration.Api.GraphQL; public class GraphQLClientExceptionHandling : IAsyncLifetime { - private Client _sut; + private IClient _sut; public Task DisposeAsync() => Task.CompletedTask; diff --git a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ActiveUserResourceTests.cs b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ActiveUserResourceTests.cs index f4f99370..c4b277d4 100644 --- a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ActiveUserResourceTests.cs +++ b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ActiveUserResourceTests.cs @@ -2,13 +2,12 @@ using Speckle.Sdk.Api; using Speckle.Sdk.Api.GraphQL.Inputs; using Speckle.Sdk.Api.GraphQL.Resources; -using Xunit; namespace Speckle.Sdk.Tests.Integration.API.GraphQL.Resources; public class ActiveUserResourceTests : IAsyncLifetime { - private Client _testUser; + private IClient _testUser; private ActiveUserResource Sut => _testUser.ActiveUser; // Setup method for xUnit using IAsyncLifetime diff --git a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/CommentResourceTests.cs b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/CommentResourceTests.cs index 80611b01..0d59bd63 100644 --- a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/CommentResourceTests.cs +++ b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/CommentResourceTests.cs @@ -4,14 +4,13 @@ using Speckle.Sdk.Api.GraphQL.Inputs; using Speckle.Sdk.Api.GraphQL.Models; using Speckle.Sdk.Api.GraphQL.Resources; using Speckle.Sdk.Common; -using Xunit; using Version = Speckle.Sdk.Api.GraphQL.Models.Version; namespace Speckle.Sdk.Tests.Integration.API.GraphQL.Resources; public class CommentResourceTests : IAsyncLifetime { - private Client _testUser; + private IClient _testUser; private CommentResource Sut; private Project _project; private Model _model; diff --git a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ModelResourceExceptionalTests.cs b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ModelResourceExceptionalTests.cs index 91c995fd..7bc3a106 100644 --- a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ModelResourceExceptionalTests.cs +++ b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ModelResourceExceptionalTests.cs @@ -4,13 +4,12 @@ using Speckle.Sdk.Api.GraphQL.Enums; using Speckle.Sdk.Api.GraphQL.Inputs; using Speckle.Sdk.Api.GraphQL.Models; using Speckle.Sdk.Api.GraphQL.Resources; -using Xunit; namespace Speckle.Sdk.Tests.Integration.API.GraphQL.Resources; public class ModelResourceExceptionalTests : IAsyncLifetime { - private Client _testUser; + private IClient _testUser; private ModelResource Sut => _testUser.Model; private Project _project; private Model _model; diff --git a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ModelResourceTests.cs b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ModelResourceTests.cs index 19051efb..0b7b9481 100644 --- a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ModelResourceTests.cs +++ b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ModelResourceTests.cs @@ -3,13 +3,12 @@ using Speckle.Sdk.Api; using Speckle.Sdk.Api.GraphQL.Inputs; using Speckle.Sdk.Api.GraphQL.Models; using Speckle.Sdk.Api.GraphQL.Resources; -using Xunit; namespace Speckle.Sdk.Tests.Integration.API.GraphQL.Resources; public class ModelResourceTests : IAsyncLifetime { - private Client _testUser; + private IClient _testUser; private ModelResource Sut => _testUser.Model; private Project _project; private Model _model; diff --git a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/OtherUserResourceTests.cs b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/OtherUserResourceTests.cs index 86e41c71..81412bd9 100644 --- a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/OtherUserResourceTests.cs +++ b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/OtherUserResourceTests.cs @@ -2,13 +2,12 @@ using Speckle.Sdk.Api; using Speckle.Sdk.Api.GraphQL.Resources; using Speckle.Sdk.Credentials; -using Xunit; namespace Speckle.Sdk.Tests.Integration.API.GraphQL.Resources; public class OtherUserResourceTests { - private readonly Client _testUser; + private readonly IClient _testUser; private readonly Account _testData; private OtherUserResource Sut => _testUser.OtherUser; diff --git a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectInviteResourceExceptionalTests.cs b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectInviteResourceExceptionalTests.cs index 23137093..878f5f7a 100644 --- a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectInviteResourceExceptionalTests.cs +++ b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectInviteResourceExceptionalTests.cs @@ -3,13 +3,12 @@ using Speckle.Sdk.Api; using Speckle.Sdk.Api.GraphQL.Inputs; using Speckle.Sdk.Api.GraphQL.Models; using Speckle.Sdk.Api.GraphQL.Resources; -using Xunit; namespace Speckle.Sdk.Tests.Integration.API.GraphQL.Resources; public class ProjectInviteResourceExceptionalTests : IAsyncLifetime { - private Client _testUser; + private IClient _testUser; private Project _project; private ProjectInviteResource Sut => _testUser.ProjectInvite; diff --git a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectInviteResourceTests.cs b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectInviteResourceTests.cs index 0a4efd57..a3c9115d 100644 --- a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectInviteResourceTests.cs +++ b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectInviteResourceTests.cs @@ -4,13 +4,12 @@ using Speckle.Sdk.Api.GraphQL; using Speckle.Sdk.Api.GraphQL.Inputs; using Speckle.Sdk.Api.GraphQL.Models; using Speckle.Sdk.Common; -using Xunit; namespace Speckle.Sdk.Tests.Integration.API.GraphQL.Resources; public class ProjectInviteResourceTests : IAsyncLifetime { - private Client _inviter, + private IClient _inviter, _invitee; private Project _project; private PendingStreamCollaborator _createdInvite; diff --git a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectResourceExceptionalTests.cs b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectResourceExceptionalTests.cs index 2fd429b3..ea669742 100644 --- a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectResourceExceptionalTests.cs +++ b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectResourceExceptionalTests.cs @@ -6,13 +6,12 @@ using Speckle.Sdk.Api.GraphQL.Inputs; using Speckle.Sdk.Api.GraphQL.Models; using Speckle.Sdk.Api.GraphQL.Resources; using Speckle.Sdk.Common; -using Xunit; namespace Speckle.Sdk.Tests.Integration.API.GraphQL.Resources; public class ProjectResourceExceptionalTests : IAsyncLifetime { - private Client _testUser, + private IClient _testUser, _secondUser, _unauthedUser; private Project _testProject; diff --git a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectResourceTests.cs b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectResourceTests.cs index 665c3ff4..8ae70e7b 100644 --- a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectResourceTests.cs +++ b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectResourceTests.cs @@ -4,13 +4,12 @@ using Speckle.Sdk.Api.GraphQL.Enums; using Speckle.Sdk.Api.GraphQL.Inputs; using Speckle.Sdk.Api.GraphQL.Models; using Speckle.Sdk.Api.GraphQL.Resources; -using Xunit; namespace Speckle.Sdk.Tests.Integration.API.GraphQL.Resources; public class ProjectResourceTests { - private readonly Client _testUser; + private readonly IClient _testUser; private readonly Project _testProject; private ProjectResource Sut => _testUser.Project; @@ -21,7 +20,7 @@ public class ProjectResourceTests (_testUser, _testProject) = setupTask.Result; } - private async Task<(Client TestUser, Project TestProject)> Setup() + private async Task<(IClient TestUser, Project TestProject)> Setup() { var testUser = await Fixtures.SeedUserWithClient(); var testProject = await testUser.Project.Create(new ProjectCreateInput("test project123", "desc", null)); @@ -30,7 +29,7 @@ public class ProjectResourceTests [Theory] [InlineData("Very private project", "My secret project", ProjectVisibility.Private)] - [InlineData("Very public project", null, ProjectVisibility.Public)] + [InlineData("Very unlisted project", null, ProjectVisibility.Unlisted)] public async Task ProjectCreate_Should_CreateProjectSuccessfully( string name, string? description, @@ -65,13 +64,13 @@ public class ProjectResourceTests result.createdAt.Should().Be(_testProject.createdAt); } - //[Fact] - private async Task ProjectUpdate_Should_UpdateProjectSuccessfully() + [Fact] + public async Task ProjectUpdate_Should_UpdateProjectSuccessfully() { // Arrange const string NEW_NAME = "MY new name"; const string NEW_DESCRIPTION = "MY new desc"; - const ProjectVisibility NEW_VISIBILITY = ProjectVisibility.Public; + const ProjectVisibility NEW_VISIBILITY = ProjectVisibility.Unlisted; // Act var newProject = await Sut.Update( diff --git a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/SubscriptionResourceTests.cs b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/SubscriptionResourceTests.cs index 9abe9cce..7fa9d068 100644 --- a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/SubscriptionResourceTests.cs +++ b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/SubscriptionResourceTests.cs @@ -4,7 +4,6 @@ using Speckle.Sdk.Api.GraphQL.Enums; using Speckle.Sdk.Api.GraphQL.Inputs; using Speckle.Sdk.Api.GraphQL.Models; using Speckle.Sdk.Api.GraphQL.Resources; -using Xunit; using Version = Speckle.Sdk.Api.GraphQL.Models.Version; namespace Speckle.Sdk.Tests.Integration.API.GraphQL.Resources; @@ -12,7 +11,7 @@ namespace Speckle.Sdk.Tests.Integration.API.GraphQL.Resources; public class SubscriptionResourceTests : IAsyncLifetime { private const int WAIT_PERIOD = 300; - private Client _testUser; + private IClient _testUser; private Project _testProject; private Model _testModel; private Version _testVersion; diff --git a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/VersionResourceTests.cs b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/VersionResourceTests.cs index 321fdd2a..46f04165 100644 --- a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/VersionResourceTests.cs +++ b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/VersionResourceTests.cs @@ -3,14 +3,13 @@ using Speckle.Sdk.Api; using Speckle.Sdk.Api.GraphQL.Inputs; using Speckle.Sdk.Api.GraphQL.Models; using Speckle.Sdk.Api.GraphQL.Resources; -using Xunit; using Version = Speckle.Sdk.Api.GraphQL.Models.Version; namespace Speckle.Sdk.Tests.Integration.API.GraphQL.Resources; public class VersionResourceTests : IAsyncLifetime { - private Client _testUser; + private IClient _testUser; private VersionResource Sut => _testUser.Version; private Project _project; private Model _model1; diff --git a/tests/Speckle.Sdk.Tests.Integration/Credentials/UserServerInfoTests.cs b/tests/Speckle.Sdk.Tests.Integration/Credentials/UserServerInfoTests.cs index 43a93be8..dad46fb6 100644 --- a/tests/Speckle.Sdk.Tests.Integration/Credentials/UserServerInfoTests.cs +++ b/tests/Speckle.Sdk.Tests.Integration/Credentials/UserServerInfoTests.cs @@ -3,7 +3,6 @@ using GraphQL.Client.Http; using Microsoft.Extensions.DependencyInjection; using Speckle.Sdk.Api.GraphQL.Models; using Speckle.Sdk.Credentials; -using Xunit; namespace Speckle.Sdk.Tests.Integration.Credentials; diff --git a/tests/Speckle.Sdk.Tests.Integration/Fixtures.cs b/tests/Speckle.Sdk.Tests.Integration/Fixtures.cs index bef9259f..a8afbc0c 100644 --- a/tests/Speckle.Sdk.Tests.Integration/Fixtures.cs +++ b/tests/Speckle.Sdk.Tests.Integration/Fixtures.cs @@ -30,17 +30,17 @@ public static class Fixtures ServiceProvider = TestServiceSetup.GetServiceProvider(); } - public static Client Unauthed => + public static IClient Unauthed => ServiceProvider .GetRequiredService() .Create(new Account { serverInfo = Server, userInfo = new UserInfo() }); - public static async Task SeedUserWithClient() + public static async Task SeedUserWithClient() { return ServiceProvider.GetRequiredService().Create(await SeedUser()); } - public static async Task CreateVersion(Client client, string projectId, string modelId) + public static async Task CreateVersion(IClient client, string projectId, string modelId) { using var remote = ServiceProvider.GetRequiredService().Create(client.Account, projectId); var (objectId, _) = await ServiceProvider @@ -157,7 +157,7 @@ public static class Fixtures return new Blob(filePath); } - internal static async Task CreateComment(Client client, string projectId, string modelId, string versionId) + internal static async Task CreateComment(IClient client, string projectId, string modelId, string versionId) { var blobs = await SendBlobData(client.Account, projectId); var blobIds = blobs.Select(b => b.id.NotNull()).ToList(); diff --git a/tests/Speckle.Sdk.Tests.Integration/MemoryTransportTests.cs b/tests/Speckle.Sdk.Tests.Integration/MemoryTransportTests.cs index 99ccf856..f1c7cc8b 100644 --- a/tests/Speckle.Sdk.Tests.Integration/MemoryTransportTests.cs +++ b/tests/Speckle.Sdk.Tests.Integration/MemoryTransportTests.cs @@ -5,7 +5,6 @@ using Speckle.Sdk.Api; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Transports; -using Xunit; namespace Speckle.Sdk.Tests.Integration; 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.Integration/packages.lock.json b/tests/Speckle.Sdk.Tests.Integration/packages.lock.json index 32c8bf35..9d7e5e45 100644 --- a/tests/Speckle.Sdk.Tests.Integration/packages.lock.json +++ b/tests/Speckle.Sdk.Tests.Integration/packages.lock.json @@ -57,6 +57,38 @@ "resolved": "3.0.2", "contentHash": "oXbusR6iPq0xlqoikjdLvzh+wQDkMv9If58myz9MEzldS4nIcp442Btgs2sWbYWV+caEluMe2pQCZ0hUZgPiow==" }, + "Argon": { + "type": "Transitive", + "resolved": "0.27.0", + "contentHash": "LtZKATYeTwDyYq1AXrgVU/ly+nI6GvE0GK1isJYFPQOnb2uHUxvDA+yh40QYaITGTLViXK7rbWhNKpbZ5pb9XA==" + }, + "Castle.Core": { + "type": "Transitive", + "resolved": "5.1.1", + "contentHash": "rpYtIczkzGpf+EkZgDr9CClTdemhsrwA/W5hMoPjLkRFnXzH44zDLoovXeKtmxb1ykXK9aJVODSpiJml8CTw2g==", + "dependencies": { + "System.Diagnostics.EventLog": "6.0.0" + } + }, + "DiffEngine": { + "type": "Transitive", + "resolved": "16.1.0", + "contentHash": "ImEFC6BN62paN0N7v8vrLY3x/LpfbJaJy5yDtL+/L2As6FI1npGJcFZwzz1A7pdDjIYPOXE91qv6BpgEUGjDkA==", + "dependencies": { + "EmptyFiles": "8.8.0", + "System.Management": "8.0.0" + } + }, + "EmptyFiles": { + "type": "Transitive", + "resolved": "8.8.0", + "contentHash": "d0pgc/vMyKgQ9T3qiiJBn1uYUSZ1/OShh6tySnNSkELRSgM4A4IOrpdQhLqwCkPwYvdJqzKuxQ6wn3MQAd4GNA==" + }, + "FSharp.Core": { + "type": "Transitive", + "resolved": "7.0.300", + "contentHash": "8vvItREJ1l5lcp3vBCSJ1mFevVAhR48I34DuF/EoUa7o1KlFpQpagyuZkVYMAsHPIjdp47ZxM9sI4eqeXaeWkA==" + }, "GraphQL.Client.Abstractions": { "type": "Transitive", "resolved": "6.0.0", @@ -171,6 +203,20 @@ "resolved": "13.0.1", "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==" }, + "Quibble": { + "type": "Transitive", + "resolved": "0.3.1", + "contentHash": "LD6bz2p+4O/BQnmD4mqFZrmdN/IjsPo1wUvfmcH46Q05ng+dyMLl3d2ylj0x412F4fpJEtm0Z3EaCAx4FqgNuQ==", + "dependencies": { + "FSharp.Core": "7.0.300", + "System.Text.Json": "7.0.3" + } + }, + "SimpleInfoName": { + "type": "Transitive", + "resolved": "3.1.0", + "contentHash": "j+ENh86NhxrgDc6T1ueqIR2QOdDkSJY2dbTFyPN/JvIXifB4GHAunlMw/x7P6m7XaXEHr3s+SMZfKBlmnmkO6g==" + }, "SQLitePCLRaw.bundle_e_sqlite3": { "type": "Transitive", "resolved": "2.1.4", @@ -201,11 +247,34 @@ "SQLitePCLRaw.core": "2.1.4" } }, + "System.CodeDom": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "WTlRjL6KWIMr/pAaq3rYqh0TJlzpouaQ/W1eelssHgtlwHAH25jXTkUphTYx9HaIIf7XA6qs/0+YhtLEQRkJ+Q==" + }, "System.ComponentModel.Annotations": { "type": "Transitive", "resolved": "4.5.0", "contentHash": "UxYQ3FGUOtzJ7LfSdnYSFd7+oEv6M8NgUatatIN2HxNtDdlcvFAf+VIq4Of9cDMJEJC0aSRv/x898RYhB4Yppg==" }, + "System.Diagnostics.EventLog": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "lcyUiXTsETK2ALsZrX+nWuHSIQeazhqPphLfaRxzdGaG93+0kELqpgEHtwWOlQe7+jSFnKwaCAgL4kjeZCQJnw==" + }, + "System.IO.Hashing": { + "type": "Transitive", + "resolved": "9.0.3", + "contentHash": "BrMGzDRLz410PE4qC8UeKeAc0hFRjBkiCUOLTwuod65NAjqg5tDNqYU7gP0A09taEXtecB+HJc1NNnnTjsKFAQ==" + }, + "System.Management": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "jrK22i5LRzxZCfGb+tGmke2VH7oE0DvcDlJ1HAKYU8cPmD8XnpUT0bYn2Gy98GEhGjtfbR/sxKTVb+dE770pfA==", + "dependencies": { + "System.CodeDom": "8.0.0" + } + }, "System.Memory": { "type": "Transitive", "resolved": "4.5.3", @@ -226,6 +295,30 @@ "resolved": "4.5.1", "contentHash": "Zh8t8oqolRaFa9vmOZfdQm/qKejdqz0J9kr7o2Fu0vPeoH3BL1EOXipKWwkWtLT1JPzjByrF19fGuFlNbmPpiw==" }, + "System.Text.Encodings.Web": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==" + }, + "System.Text.Json": { + "type": "Transitive", + "resolved": "8.0.4", + "contentHash": "bAkhgDJ88XTsqczoxEMliSrpijKZHhbJQldhAmObj/RbrN3sU5dcokuXmWJWsdQAhiMJ9bTayWsL1C9fbbCRhw==", + "dependencies": { + "System.Text.Encodings.Web": "8.0.0" + } + }, + "Verify": { + "type": "Transitive", + "resolved": "29.2.0", + "contentHash": "EhhwhXIeip9AJGWRPXh47NAUoiELnWzeBnAzFSl0+ryAfijTV1T+B4m6P6GbheWQ1CJ1cC1ZFLzgH276D5Bu3A==", + "dependencies": { + "Argon": "0.27.0", + "DiffEngine": "16.1.0", + "SimpleInfoName": "3.1.0", + "System.IO.Hashing": "9.0.3" + } + }, "xunit.abstractions": { "type": "Transitive", "resolved": "2.0.3", @@ -277,24 +370,37 @@ "speckle.sdk.dependencies": { "type": "Project" }, + "speckle.sdk.testing": { + "type": "Project", + "dependencies": { + "Microsoft.NET.Test.Sdk": "[17.13.0, )", + "Moq": "[4.20.72, )", + "Speckle.Sdk": "[1.0.0, )", + "Verify.Quibble": "[2.1.1, )", + "Verify.Xunit": "[29.2.0, )", + "xunit": "[2.9.3, )", + "xunit.runner.visualstudio": "[3.0.2, )" + } + }, "speckle.sdk.tests.unit": { "type": "Project", "dependencies": { - "AwesomeAssertions": "[8.0.0, )", + "AwesomeAssertions": "[8.1.0, )", "Microsoft.Extensions.DependencyInjection": "[2.2.0, )", "Microsoft.NET.Test.Sdk": "[17.13.0, )", + "RichardSzalay.MockHttp": "[7.0.0, )", "Speckle.DoubleNumerics": "[4.1.0, )", "Speckle.Sdk": "[1.0.0, )", + "Speckle.Sdk.Testing": "[1.0.0, )", "altcover": "[9.0.1, )", - "xunit": "[2.9.3, )", "xunit.runner.visualstudio": "[3.0.2, )" } }, "AwesomeAssertions": { "type": "CentralTransitive", - "requested": "[8.0.0, )", - "resolved": "8.0.0", - "contentHash": "6fWiV7mGZUzZXzeiW3hWF0nJokuuNm4hnzuqbM3IXHqGYkWnHl65+wNpuQ73xfJXClX0fmfKcTdQ2Ula719IDg==" + "requested": "[8.1.0, )", + "resolved": "8.1.0", + "contentHash": "IfNC4cpXPi9tclWvuNO9lfkuIxJsUTLTS1NXto55jDrAUQJYl0zLI9ByISrfkbBE2Xtg+IWaAXQ6jnUx3anDuw==" }, "GraphQL.Client": { "type": "CentralTransitive", @@ -350,6 +456,21 @@ "Microsoft.Extensions.Options": "2.2.0" } }, + "Moq": { + "type": "CentralTransitive", + "requested": "[4.20.72, )", + "resolved": "4.20.72", + "contentHash": "EA55cjyNn8eTNWrgrdZJH5QLFp2L43oxl1tlkoYUKIE9pRwL784OWiTXeCV5ApS+AMYEAlt7Fo03A2XfouvHmQ==", + "dependencies": { + "Castle.Core": "5.1.1" + } + }, + "RichardSzalay.MockHttp": { + "type": "CentralTransitive", + "requested": "[7.0.0, )", + "resolved": "7.0.0", + "contentHash": "QwnauYiaywp65QKFnP+wvgiQ2D8Pv888qB2dyfd7MSVDF06sIvxqASenk+RxsWybyyt+Hu1Y251wQxpHTv3UYg==" + }, "Speckle.DoubleNumerics": { "type": "CentralTransitive", "requested": "[4.1.0, )", @@ -362,6 +483,32 @@ "resolved": "13.0.2", "contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA==" }, + "Verify.Quibble": { + "type": "CentralTransitive", + "requested": "[2.1.1, )", + "resolved": "2.1.1", + "contentHash": "Z8bVwFICa3Dog6Mcnx0wlrn4Y+CFpQXx1f+ijfLn6/v4q00q+jLm9Gu/nVyUFuc75cjn6ieI08UrqXKcR9fTYw==", + "dependencies": { + "Quibble": "0.3.1", + "System.Text.Json": "8.0.4", + "Verify": "26.1.1" + } + }, + "Verify.Xunit": { + "type": "CentralTransitive", + "requested": "[29.2.0, )", + "resolved": "29.2.0", + "contentHash": "MdcslVf40AzSA319ZHMzR+U4JqyquX28JFSrI9zA89yeZNaNcaSIb5PmE0XZ6p60Iy7eRYtnGEgSDimEUeXHZw==", + "dependencies": { + "Argon": "0.27.0", + "DiffEngine": "16.1.0", + "SimpleInfoName": "3.1.0", + "System.IO.Hashing": "9.0.3", + "Verify": "29.2.0", + "xunit.abstractions": "2.0.3", + "xunit.extensibility.execution": "2.9.3" + } + }, "xunit.assert": { "type": "CentralTransitive", "requested": "[2.9.3, )", diff --git a/tests/Speckle.Sdk.Tests.Performance/Benchmarks/GeneralSendTest.cs b/tests/Speckle.Sdk.Tests.Performance/Benchmarks/GeneralSendTest.cs index 994ea723..7f4564c3 100644 --- a/tests/Speckle.Sdk.Tests.Performance/Benchmarks/GeneralSendTest.cs +++ b/tests/Speckle.Sdk.Tests.Performance/Benchmarks/GeneralSendTest.cs @@ -26,7 +26,7 @@ public class GeneralSendTest private IOperations _operations; private ServerTransport _remote; private Account acc; - private Client client; + private IClient client; private Project _project; @@ -57,7 +57,7 @@ public class GeneralSendTest client = TestDataHelper.ServiceProvider.GetRequiredService().Create(acc); _project = await client.Project.Create( - new($"General Send Test run {Guid.NewGuid()}", null, ProjectVisibility.Public) + new($"General Send Test run {Guid.NewGuid()}", null, ProjectVisibility.Unlisted) ); _remote = TestDataHelper.ServiceProvider.GetRequiredService().Create(acc, _project.id); } 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/Api/ClientResiliencyPolicyTest.cs b/tests/Speckle.Sdk.Tests.Unit/Api/ClientResiliencyPolicyTest.cs index af764b5d..7b6d9748 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Api/ClientResiliencyPolicyTest.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Api/ClientResiliencyPolicyTest.cs @@ -4,7 +4,6 @@ using Microsoft.Extensions.DependencyInjection; using Speckle.Sdk.Api; using Speckle.Sdk.Api.GraphQL.Models; using Speckle.Sdk.Credentials; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Api; @@ -15,18 +14,19 @@ public sealed class GraphQLClientTests : IDisposable public GraphQLClientTests() { var serviceProvider = TestServiceSetup.GetServiceProvider(); - _client = serviceProvider - .GetRequiredService() - .Create( - new Account - { - token = "this is a scam", - serverInfo = new ServerInfo { url = "http://goto.testing" }, - } - ); + _client = (Client) + serviceProvider + .GetRequiredService() + .Create( + new Account + { + token = "this is a scam", + serverInfo = new ServerInfo { url = "http://goto.testing" }, + } + ); } - public void Dispose() => _client?.Dispose(); + public void Dispose() => _client.Dispose(); [Fact] public async Task TestExecuteWithResiliencePoliciesDoesntRetryTaskCancellation() diff --git a/tests/Speckle.Sdk.Tests.Unit/Api/GraphQL/ClientTests.cs b/tests/Speckle.Sdk.Tests.Unit/Api/GraphQL/ClientTests.cs new file mode 100644 index 00000000..3739c9fc --- /dev/null +++ b/tests/Speckle.Sdk.Tests.Unit/Api/GraphQL/ClientTests.cs @@ -0,0 +1,48 @@ +using FluentAssertions; +using GraphQL; +using Microsoft.Extensions.Logging; +using Moq; +using RichardSzalay.MockHttp; +using Speckle.Sdk.Api; +using Speckle.Sdk.Api.GraphQL.Models; +using Speckle.Sdk.Credentials; +using Speckle.Sdk.Helpers; +using Speckle.Sdk.Logging; +using Speckle.Sdk.Testing; + +namespace Speckle.Sdk.Tests.Unit.Api.GraphQL; + +public class ClientTests : MoqTest +{ + [Fact] + //basic end to end GraphQL test as is. Avoids a proper request/response + public async Task ExecuteGraphQLRequest() + { + using var mockHandler = new MockHttpMessageHandler(); + mockHandler.When(HttpMethod.Post, "https://speckle.xyz/graphql").Respond("application/json", "{}"); + var httpClient = mockHandler.ToHttpClient(); + var token = "token"; + var uri = new Uri("https://speckle.xyz"); + + var speckleHttp = Create(); + speckleHttp.Setup(x => x.CreateHttpClient(null, 30, token)).Returns(httpClient); + + var application = Create(); + application.Setup(x => x.ApplicationAndVersion).Returns("test"); + + using var client = new Client( + Create>(MockBehavior.Loose).Object, + Create(MockBehavior.Loose).Object, + application.Object, + speckleHttp.Object, + new Account() + { + token = token, + serverInfo = new ServerInfo() { url = uri.AbsoluteUri }, + } + ); + + var x = await client.ExecuteGraphQLRequest(new GraphQLRequest(), CancellationToken.None); + x.Should().BeNull(); + } +} diff --git a/tests/Speckle.Sdk.Tests.Unit/Api/GraphQLErrorHandler.cs b/tests/Speckle.Sdk.Tests.Unit/Api/GraphQLErrorHandler.cs index 3a06614f..a41f8c10 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Api/GraphQLErrorHandler.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Api/GraphQLErrorHandler.cs @@ -2,7 +2,6 @@ using GraphQL; using Speckle.Sdk.Api; using Speckle.Sdk.Api.GraphQL; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Api; diff --git a/tests/Speckle.Sdk.Tests.Unit/Api/Operations/ClosureTests.cs b/tests/Speckle.Sdk.Tests.Unit/Api/Operations/ClosureTests.cs index 1240254e..1397a9ec 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Api/Operations/ClosureTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Api/Operations/ClosureTests.cs @@ -7,7 +7,6 @@ using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Tests.Unit.Host; using Speckle.Sdk.Transports; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Api.Operations; diff --git a/tests/Speckle.Sdk.Tests.Unit/Api/Operations/OperationsReceiveTests.Exceptional.cs b/tests/Speckle.Sdk.Tests.Unit/Api/Operations/OperationsReceiveTests.Exceptional.cs index 1079ef52..00288a36 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Api/Operations/OperationsReceiveTests.Exceptional.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Api/Operations/OperationsReceiveTests.Exceptional.cs @@ -1,5 +1,4 @@ using Speckle.Sdk.Transports; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Api.Operations; diff --git a/tests/Speckle.Sdk.Tests.Unit/Api/Operations/OperationsReceiveTests.cs b/tests/Speckle.Sdk.Tests.Unit/Api/Operations/OperationsReceiveTests.cs index 8df3a466..8ca3a9a9 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Api/Operations/OperationsReceiveTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Api/Operations/OperationsReceiveTests.cs @@ -4,7 +4,6 @@ using Speckle.Sdk.Api; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Transports; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Api.Operations; diff --git a/tests/Speckle.Sdk.Tests.Unit/Api/Operations/SendObjectReferences.cs b/tests/Speckle.Sdk.Tests.Unit/Api/Operations/SendObjectReferences.cs index 3e402fc8..94704b0c 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Api/Operations/SendObjectReferences.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Api/Operations/SendObjectReferences.cs @@ -4,7 +4,6 @@ using Speckle.Sdk.Api; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Transports; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Api.Operations; diff --git a/tests/Speckle.Sdk.Tests.Unit/Api/Operations/SendReceiveLocal.cs b/tests/Speckle.Sdk.Tests.Unit/Api/Operations/SendReceiveLocal.cs index 813d9307..ab85188d 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Api/Operations/SendReceiveLocal.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Api/Operations/SendReceiveLocal.cs @@ -6,7 +6,6 @@ using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Tests.Unit.Host; using Speckle.Sdk.Transports; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Api.Operations; diff --git a/tests/Speckle.Sdk.Tests.Unit/Api/Operations/SerializationTests.cs b/tests/Speckle.Sdk.Tests.Unit/Api/Operations/SerializationTests.cs index b5dc30fe..b119382d 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Api/Operations/SerializationTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Api/Operations/SerializationTests.cs @@ -5,7 +5,6 @@ using Speckle.Sdk.Api; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Tests.Unit.Host; -using Xunit; using Point = Speckle.Sdk.Tests.Unit.Host.Point; namespace Speckle.Sdk.Tests.Unit.Api.Operations; diff --git a/tests/Speckle.Sdk.Tests.Unit/Assembly.cs b/tests/Speckle.Sdk.Tests.Unit/Assembly.cs index a4bcec54..c7fc3b1f 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Assembly.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Assembly.cs @@ -1,3 +1 @@ -using Xunit; - -[assembly: CollectionBehavior(DisableTestParallelization = true)] +[assembly: CollectionBehavior(DisableTestParallelization = true)] diff --git a/tests/Speckle.Sdk.Tests.Unit/Common/NotNullTests.cs b/tests/Speckle.Sdk.Tests.Unit/Common/NotNullTests.cs index a9ac02d5..3dc8f2ce 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Common/NotNullTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Common/NotNullTests.cs @@ -1,6 +1,5 @@ using FluentAssertions; using Speckle.Sdk.Common; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Common; diff --git a/tests/Speckle.Sdk.Tests.Unit/Common/RangeFromTests.cs b/tests/Speckle.Sdk.Tests.Unit/Common/RangeFromTests.cs index 575277bd..05be88c9 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Common/RangeFromTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Common/RangeFromTests.cs @@ -1,5 +1,4 @@ using Speckle.Sdk.Dependencies; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Common; diff --git a/tests/Speckle.Sdk.Tests.Unit/Common/UnitsTest.cs b/tests/Speckle.Sdk.Tests.Unit/Common/UnitsTest.cs index 3f8caa7c..538a4b87 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Common/UnitsTest.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Common/UnitsTest.cs @@ -1,6 +1,5 @@ using FluentAssertions; using Speckle.Sdk.Common; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Common; diff --git a/tests/Speckle.Sdk.Tests.Unit/Credentials/AccountServerMigrationTests.cs b/tests/Speckle.Sdk.Tests.Unit/Credentials/AccountServerMigrationTests.cs index b61eae75..ccf8a553 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Credentials/AccountServerMigrationTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Credentials/AccountServerMigrationTests.cs @@ -2,7 +2,6 @@ using FluentAssertions; using Microsoft.Extensions.DependencyInjection; using Speckle.Sdk.Api.GraphQL.Models; using Speckle.Sdk.Credentials; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Credentials; diff --git a/tests/Speckle.Sdk.Tests.Unit/Credentials/Accounts.cs b/tests/Speckle.Sdk.Tests.Unit/Credentials/Accounts.cs index ac9df5f0..ad18d9d2 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Credentials/Accounts.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Credentials/Accounts.cs @@ -2,7 +2,6 @@ using FluentAssertions; using Microsoft.Extensions.DependencyInjection; using Speckle.Sdk.Api.GraphQL.Models; using Speckle.Sdk.Credentials; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Credentials; diff --git a/tests/Speckle.Sdk.Tests.Unit/Helpers/Path.cs b/tests/Speckle.Sdk.Tests.Unit/Helpers/Path.cs index 422dcbbe..73280f59 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Helpers/Path.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Helpers/Path.cs @@ -1,7 +1,6 @@ using System.Runtime.InteropServices; using FluentAssertions; using Speckle.Sdk.Logging; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Helpers; diff --git a/tests/Speckle.Sdk.Tests.Unit/Helpers/SpeckleHttpTests.cs b/tests/Speckle.Sdk.Tests.Unit/Helpers/SpeckleHttpTests.cs new file mode 100644 index 00000000..5b03545c --- /dev/null +++ b/tests/Speckle.Sdk.Tests.Unit/Helpers/SpeckleHttpTests.cs @@ -0,0 +1,66 @@ +using System.Net; +using FluentAssertions; +using Microsoft.Extensions.Logging; +using Moq; +using RichardSzalay.MockHttp; +using Speckle.Sdk.Helpers; +using Speckle.Sdk.Testing; + +namespace Speckle.Sdk.Tests.Unit.Helpers; + +public class SpeckleHttpTests : MoqTest +{ + [Fact] + public async Task HttpPing() + { + using var mockHttp = new MockHttpMessageHandler(); + var speckleHttp = new SpeckleHttp( + Create>(MockBehavior.Loose).Object, + Create().Object + ); + + var uri = new Uri("https://speckle.xyz"); + mockHttp.When(uri.AbsoluteUri).Respond("application/json", "{}"); + var response = await speckleHttp.HttpPing(uri, mockHttp.ToHttpClient()); + response.Should().NotBeNull(); + } + + [Fact] + public async Task HttpPing_Failed() + { + using var mockHttp = new MockHttpMessageHandler(); + var speckleHttp = new SpeckleHttp( + Create>(MockBehavior.Loose).Object, + Create().Object + ); + + var uri = new Uri("https://speckle.xyz"); + mockHttp.When(uri.AbsoluteUri).Respond(HttpStatusCode.Unauthorized); + await Assert.ThrowsAsync( + async () => await speckleHttp.HttpPing(uri, mockHttp.ToHttpClient()) + ); + } + + [Fact] + public void CreateHttpClient_NoToken() + { + var clientHandlerFactory = Create(); + + using var mockHttp1 = new MockHttpMessageHandler(); + using var mockHttp2 = new MockHttpMessageHandler(); + var speckleHandler = Create(); + + clientHandlerFactory + .Setup(x => x.Create(mockHttp1, SpeckleHttp.DEFAULT_TIMEOUT_SECONDS)) + .Returns(speckleHandler.Object); + + var speckleHttp = new SpeckleHttp( + Create>(MockBehavior.Loose).Object, + clientHandlerFactory.Object + ); + + var client = speckleHttp.CreateHttpClient(mockHttp1); + client.Should().NotBeNull(); + client.DefaultRequestHeaders.Should().BeEmpty(); + } +} 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 87d5aa3c..00000000 --- a/tests/Speckle.Sdk.Tests.Unit/Host/HostApplicationTests.cs +++ /dev/null @@ -1,22 +0,0 @@ -using FluentAssertions; -using Speckle.Sdk.Host; -using Xunit; - -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/Models/BaseTests.cs b/tests/Speckle.Sdk.Tests.Unit/Models/BaseTests.cs index c658b48a..16812c12 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Models/BaseTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Models/BaseTests.cs @@ -2,7 +2,6 @@ using FluentAssertions; using Speckle.Sdk.Common; using Speckle.Sdk.Host; using Speckle.Sdk.Models; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Models; @@ -120,7 +119,6 @@ public class BaseTests var dynamicProp = "dynamicProp"; @base[dynamicProp] = 123; var names = @base.GetMembers().Keys; - names.Should().NotContain(nameof(@base.IgnoredSchemaProp)); names.Should().NotContain(nameof(@base.ObsoleteSchemaProp)); names.Should().Contain(dynamicProp); names.Should().Contain(nameof(@base.attachedProp)); @@ -154,7 +152,7 @@ public class BaseTests var @base = new SampleObject(); @base["dynamicProp"] = 123; - var names = @base.GetMembers(DynamicBaseMemberType.Instance | DynamicBaseMemberType.SchemaIgnored).Keys; + var names = @base.GetMembers(DynamicBaseMemberType.Instance).Keys; names.Should().Contain(nameof(@base.IgnoredSchemaProp)); names.Should().Contain(nameof(@base.attachedProp)); } @@ -208,8 +206,7 @@ public class BaseTests var sample = new SampleObject(); var copy = sample.ShallowCopy(); - var selectedMembers = - DynamicBaseMemberType.Dynamic | DynamicBaseMemberType.Instance | DynamicBaseMemberType.SchemaIgnored; + var selectedMembers = DynamicBaseMemberType.Dynamic | DynamicBaseMemberType.Instance; var sampleMembers = sample.GetMembers(selectedMembers); var copyMembers = copy.GetMembers(selectedMembers); @@ -232,8 +229,6 @@ public class BaseTests public SampleProp attachedProp { get; set; } public string crazyProp { get; set; } - - [SchemaIgnore] public string IgnoredSchemaProp { get; set; } [Obsolete("Use attached prop")] diff --git a/tests/Speckle.Sdk.Tests.Unit/Models/Extensions/BaseExtensionsTests.cs b/tests/Speckle.Sdk.Tests.Unit/Models/Extensions/BaseExtensionsTests.cs index f0a24de5..c98d946d 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Models/Extensions/BaseExtensionsTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Models/Extensions/BaseExtensionsTests.cs @@ -3,7 +3,6 @@ using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Models.Collections; using Speckle.Sdk.Models.Extensions; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Models.Extensions; @@ -12,7 +11,7 @@ public class BaseExtensionsTests public BaseExtensionsTests() { TypeLoader.Reset(); - TypeLoader.Initialize(typeof(Base).Assembly); + TypeLoader.Initialize(typeof(Base).Assembly, typeof(TestBase).Assembly); } [Theory] diff --git a/tests/Speckle.Sdk.Tests.Unit/Models/Extensions/DisplayValueTests.cs b/tests/Speckle.Sdk.Tests.Unit/Models/Extensions/DisplayValueTests.cs index b000afcc..a66c3f64 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Models/Extensions/DisplayValueTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Models/Extensions/DisplayValueTests.cs @@ -2,7 +2,6 @@ using FluentAssertions; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Models.Extensions; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Models.Extensions; diff --git a/tests/Speckle.Sdk.Tests.Unit/Models/Extensions/ExceptionTests.cs b/tests/Speckle.Sdk.Tests.Unit/Models/Extensions/ExceptionTests.cs index 4b5c3750..317080a1 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Models/Extensions/ExceptionTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Models/Extensions/ExceptionTests.cs @@ -1,6 +1,5 @@ using FluentAssertions; using Speckle.Sdk.Models.Extensions; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Models.Extensions; diff --git a/tests/Speckle.Sdk.Tests.Unit/Models/GraphTraversal/GraphTraversalTests.cs b/tests/Speckle.Sdk.Tests.Unit/Models/GraphTraversal/GraphTraversalTests.cs index 945102a4..5771daf3 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Models/GraphTraversal/GraphTraversalTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Models/GraphTraversal/GraphTraversalTests.cs @@ -3,7 +3,6 @@ using FluentAssertions; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Models.GraphTraversal; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Models.GraphTraversal; diff --git a/tests/Speckle.Sdk.Tests.Unit/Models/GraphTraversal/TraversalContextExtensionsTests.cs b/tests/Speckle.Sdk.Tests.Unit/Models/GraphTraversal/TraversalContextExtensionsTests.cs index d8c6f072..f1841970 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Models/GraphTraversal/TraversalContextExtensionsTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Models/GraphTraversal/TraversalContextExtensionsTests.cs @@ -3,7 +3,6 @@ using Speckle.Sdk.Common; using Speckle.Sdk.Models; using Speckle.Sdk.Models.Collections; using Speckle.Sdk.Models.GraphTraversal; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Models.GraphTraversal; diff --git a/tests/Speckle.Sdk.Tests.Unit/Models/Hashing.cs b/tests/Speckle.Sdk.Tests.Unit/Models/Hashing.cs index decd2b33..9de09c2d 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Models/Hashing.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Models/Hashing.cs @@ -3,7 +3,6 @@ using FluentAssertions; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Tests.Unit.Host; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Models; diff --git a/tests/Speckle.Sdk.Tests.Unit/Models/SpeckleType.cs b/tests/Speckle.Sdk.Tests.Unit/Models/SpeckleType.cs index 63500570..b92de3c3 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Models/SpeckleType.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Models/SpeckleType.cs @@ -2,7 +2,6 @@ using FluentAssertions; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Tests.Unit.Models.TestModels; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Models { diff --git a/tests/Speckle.Sdk.Tests.Unit/Models/TraversalTests.cs b/tests/Speckle.Sdk.Tests.Unit/Models/TraversalTests.cs index da0c804b..ef705359 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Models/TraversalTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Models/TraversalTests.cs @@ -2,7 +2,6 @@ using FluentAssertions; using Speckle.Sdk.Common; using Speckle.Sdk.Models; using Speckle.Sdk.Models.Extensions; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Models; diff --git a/tests/Speckle.Sdk.Tests.Unit/Models/UtilitiesTests.cs b/tests/Speckle.Sdk.Tests.Unit/Models/UtilitiesTests.cs index 72f71821..32bf1d17 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Models/UtilitiesTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Models/UtilitiesTests.cs @@ -1,7 +1,6 @@ using FluentAssertions; using Speckle.Sdk.Dependencies; using Speckle.Sdk.Helpers; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Models; diff --git a/tests/Speckle.Sdk.Tests.Unit/SQLite/SQLiteJsonCacheManagerTests.cs b/tests/Speckle.Sdk.Tests.Unit/SQLite/SQLiteJsonCacheManagerTests.cs index 49c2a549..6496451e 100644 --- a/tests/Speckle.Sdk.Tests.Unit/SQLite/SQLiteJsonCacheManagerTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/SQLite/SQLiteJsonCacheManagerTests.cs @@ -1,6 +1,5 @@ using FluentAssertions; using Speckle.Sdk.SQLite; -using Xunit; namespace Speckle.Sdk.Tests.Unit.SQLite; diff --git a/tests/Speckle.Sdk.Tests.Unit/SQLite/SQLiteJsonExceptionTests.cs b/tests/Speckle.Sdk.Tests.Unit/SQLite/SQLiteJsonExceptionTests.cs index 91721a95..434aa223 100644 --- a/tests/Speckle.Sdk.Tests.Unit/SQLite/SQLiteJsonExceptionTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/SQLite/SQLiteJsonExceptionTests.cs @@ -1,6 +1,5 @@ using Microsoft.Data.Sqlite; using Speckle.Sdk.SQLite; -using Xunit; namespace Speckle.Sdk.Tests.Unit.SQLite; diff --git a/tests/Speckle.Sdk.Tests.Unit/Serialisation/BatchTests.cs b/tests/Speckle.Sdk.Tests.Unit/Serialisation/BatchTests.cs index de6f38a0..bef03770 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Serialisation/BatchTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Serialisation/BatchTests.cs @@ -1,7 +1,6 @@ using FluentAssertions; using Speckle.Sdk.Dependencies; using Speckle.Sdk.Serialisation.V2.Send; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Serialisation; @@ -12,8 +11,6 @@ public class BatchTests public int ByteSize { get; } = size; } - private static readonly Action EMPTY_LOGGER = _ => { }; - [Fact] public void TestBatchSize_Calc() { @@ -24,16 +21,6 @@ public class BatchTests batch.BatchByteSize.Should().Be(3); } - [Fact] - public void Ensure_logging() - { - using var batch = new Batch(); - batch.AddBatchItem(new BatchItem(2)); - bool called = false; - batch.GetBatchSize(x => called = true, 1); - called.Should().BeTrue(); - } - [Fact] public void TestBatchSize_Trim() { @@ -76,13 +63,13 @@ public class BatchTests using var batch = BatchExtensions.CreateBatch(); batch.AddBatchItem(new BatchItem(2)); - bool full = batch.GetBatchSize(EMPTY_LOGGER, MAX_BATCH_SIZE) == MAX_BATCH_SIZE; + bool full = batch.GetBatchSize(MAX_BATCH_SIZE) == MAX_BATCH_SIZE; full.Should().BeFalse(); batch.AddBatchItem(new BatchItem(2)); - full = batch.GetBatchSize(EMPTY_LOGGER, MAX_BATCH_SIZE) == MAX_BATCH_SIZE; + full = batch.GetBatchSize(MAX_BATCH_SIZE) == MAX_BATCH_SIZE; full.Should().BeFalse(); batch.AddBatchItem(new BatchItem(2)); - full = batch.GetBatchSize(EMPTY_LOGGER, MAX_BATCH_SIZE) == MAX_BATCH_SIZE; + full = batch.GetBatchSize(MAX_BATCH_SIZE) == MAX_BATCH_SIZE; full.Should().BeTrue(); } @@ -93,7 +80,7 @@ public class BatchTests using var batch = BatchExtensions.CreateBatch(); batch.AddBatchItem(new BatchItem(63)); - bool full = batch.GetBatchSize(EMPTY_LOGGER, MAX_BATCH_SIZE) == MAX_BATCH_SIZE; + bool full = batch.GetBatchSize(MAX_BATCH_SIZE) == MAX_BATCH_SIZE; full.Should().BeTrue(); } @@ -104,10 +91,10 @@ public class BatchTests using var batch = BatchExtensions.CreateBatch(); batch.AddBatchItem(new BatchItem(2)); - bool full = batch.GetBatchSize(EMPTY_LOGGER, MAX_BATCH_SIZE) == MAX_BATCH_SIZE; + bool full = batch.GetBatchSize(MAX_BATCH_SIZE) == MAX_BATCH_SIZE; full.Should().BeFalse(); batch.AddBatchItem(new BatchItem(63)); - full = batch.GetBatchSize(EMPTY_LOGGER, MAX_BATCH_SIZE) == MAX_BATCH_SIZE; + full = batch.GetBatchSize(MAX_BATCH_SIZE) == MAX_BATCH_SIZE; full.Should().BeTrue(); } } diff --git a/tests/Speckle.Sdk.Tests.Unit/Serialisation/ChunkingTests.cs b/tests/Speckle.Sdk.Tests.Unit/Serialisation/ChunkingTests.cs index 7eb55588..3fa44af0 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Serialisation/ChunkingTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Serialisation/ChunkingTests.cs @@ -4,7 +4,6 @@ using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Serialisation; using Speckle.Sdk.Transports; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Serialisation; diff --git a/tests/Speckle.Sdk.Tests.Unit/Serialisation/JsonIgnoreAttributeTests.cs b/tests/Speckle.Sdk.Tests.Unit/Serialisation/JsonIgnoreAttributeTests.cs index 2b03a901..7861b723 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Serialisation/JsonIgnoreAttributeTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Serialisation/JsonIgnoreAttributeTests.cs @@ -5,7 +5,6 @@ using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Serialisation; using Speckle.Sdk.Transports; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Serialisation; diff --git a/tests/Speckle.Sdk.Tests.Unit/Serialisation/ObjectModelDeprecationTests.cs b/tests/Speckle.Sdk.Tests.Unit/Serialisation/ObjectModelDeprecationTests.cs index eae0825c..350651bd 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Serialisation/ObjectModelDeprecationTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Serialisation/ObjectModelDeprecationTests.cs @@ -2,7 +2,6 @@ using FluentAssertions; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Serialisation.Deprecated; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Serialisation { diff --git a/tests/Speckle.Sdk.Tests.Unit/Serialisation/SerializerBreakingChanges.cs b/tests/Speckle.Sdk.Tests.Unit/Serialisation/SerializerBreakingChanges.cs index a2510abe..93eec8cf 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Serialisation/SerializerBreakingChanges.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Serialisation/SerializerBreakingChanges.cs @@ -5,7 +5,6 @@ using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Serialisation; using Speckle.Sdk.Tests.Unit.Host; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Serialisation; diff --git a/tests/Speckle.Sdk.Tests.Unit/Serialisation/SerializerNonBreakingChanges.cs b/tests/Speckle.Sdk.Tests.Unit/Serialisation/SerializerNonBreakingChanges.cs index 42397f93..ba7b231c 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Serialisation/SerializerNonBreakingChanges.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Serialisation/SerializerNonBreakingChanges.cs @@ -5,7 +5,6 @@ using Speckle.Sdk.Api; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Serialisation; -using Xunit; using Matrix4x4 = Speckle.DoubleNumerics.Matrix4x4; namespace Speckle.Sdk.Tests.Unit.Serialisation; diff --git a/tests/Speckle.Sdk.Tests.Unit/Serialisation/SimpleRoundTripTests.cs b/tests/Speckle.Sdk.Tests.Unit/Serialisation/SimpleRoundTripTests.cs index dc6e8cb2..16d80a9e 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Serialisation/SimpleRoundTripTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Serialisation/SimpleRoundTripTests.cs @@ -1,11 +1,8 @@ -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; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Serialisation; @@ -15,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/Speckle.Sdk.Tests.Unit.csproj b/tests/Speckle.Sdk.Tests.Unit/Speckle.Sdk.Tests.Unit.csproj index 5449b7dc..92ef4b7c 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Speckle.Sdk.Tests.Unit.csproj +++ b/tests/Speckle.Sdk.Tests.Unit/Speckle.Sdk.Tests.Unit.csproj @@ -10,14 +10,15 @@ + - + 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 d903a902..00000000 --- a/tests/Speckle.Sdk.Tests.Unit/Transports/DiskTransportTests.cs +++ /dev/null @@ -1,40 +0,0 @@ -using FluentAssertions; -using Speckle.Sdk.Common; -using Speckle.Sdk.Transports; -using Xunit; - -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); - } - } -} diff --git a/tests/Speckle.Sdk.Tests.Unit/Transports/MemoryTransportTests.cs b/tests/Speckle.Sdk.Tests.Unit/Transports/MemoryTransportTests.cs index e457c1a7..a3567f69 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Transports/MemoryTransportTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Transports/MemoryTransportTests.cs @@ -3,7 +3,6 @@ using FluentAssertions; using Speckle.Sdk.Common; using Speckle.Sdk.Transports; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Transports; diff --git a/tests/Speckle.Sdk.Tests.Unit/Transports/SQLiteTransport2Tests.cs b/tests/Speckle.Sdk.Tests.Unit/Transports/SQLiteTransport2Tests.cs index e4d20cf4..5b82d283 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Transports/SQLiteTransport2Tests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Transports/SQLiteTransport2Tests.cs @@ -3,7 +3,6 @@ using Microsoft.Data.Sqlite; using Speckle.Sdk.Common; using Speckle.Sdk.Serialisation.Utilities; using Speckle.Sdk.Transports; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Transports; diff --git a/tests/Speckle.Sdk.Tests.Unit/Transports/SQLiteTransportTests.cs b/tests/Speckle.Sdk.Tests.Unit/Transports/SQLiteTransportTests.cs index 1a385466..9c759b6f 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Transports/SQLiteTransportTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Transports/SQLiteTransportTests.cs @@ -1,7 +1,6 @@ using FluentAssertions; using Microsoft.Data.Sqlite; using Speckle.Sdk.Transports; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Transports; diff --git a/tests/Speckle.Sdk.Tests.Unit/Transports/TransportTests.cs b/tests/Speckle.Sdk.Tests.Unit/Transports/TransportTests.cs index 2aa32fdf..4a409b1b 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Transports/TransportTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Transports/TransportTests.cs @@ -2,7 +2,6 @@ using FluentAssertions; using Speckle.Newtonsoft.Json; using Speckle.Sdk.Common; using Speckle.Sdk.Transports; -using Xunit; namespace Speckle.Sdk.Tests.Unit.Transports; diff --git a/tests/Speckle.Sdk.Tests.Unit/packages.lock.json b/tests/Speckle.Sdk.Tests.Unit/packages.lock.json index 07972a13..f3b02a2e 100644 --- a/tests/Speckle.Sdk.Tests.Unit/packages.lock.json +++ b/tests/Speckle.Sdk.Tests.Unit/packages.lock.json @@ -10,9 +10,9 @@ }, "AwesomeAssertions": { "type": "Direct", - "requested": "[8.0.0, )", - "resolved": "8.0.0", - "contentHash": "6fWiV7mGZUzZXzeiW3hWF0nJokuuNm4hnzuqbM3IXHqGYkWnHl65+wNpuQ73xfJXClX0fmfKcTdQ2Ula719IDg==" + "requested": "[8.1.0, )", + "resolved": "8.1.0", + "contentHash": "IfNC4cpXPi9tclWvuNO9lfkuIxJsUTLTS1NXto55jDrAUQJYl0zLI9ByISrfkbBE2Xtg+IWaAXQ6jnUx3anDuw==" }, "Microsoft.Extensions.DependencyInjection": { "type": "Direct", @@ -49,6 +49,12 @@ "resolved": "1.15.0", "contentHash": "FbU0El+EEjdpuIX4iDbeS7ki1uzpJPx8vbqOzEtqnl1GZeAGJfq+jCbxeJL2y0EPnUNk8dRnnqR2xnYXg9Tf+g==" }, + "RichardSzalay.MockHttp": { + "type": "Direct", + "requested": "[7.0.0, )", + "resolved": "7.0.0", + "contentHash": "QwnauYiaywp65QKFnP+wvgiQ2D8Pv888qB2dyfd7MSVDF06sIvxqASenk+RxsWybyyt+Hu1Y251wQxpHTv3UYg==" + }, "Speckle.DoubleNumerics": { "type": "Direct", "requested": "[4.1.0, )", @@ -61,23 +67,44 @@ "resolved": "0.9.6", "contentHash": "HKH7tYrYYlCK1ct483hgxERAdVdMtl7gUKW9ijWXxA1UsYR4Z+TrRHYmzZ9qmpu1NnTycSrp005NYM78GDKV1w==" }, - "xunit": { - "type": "Direct", - "requested": "[2.9.3, )", - "resolved": "2.9.3", - "contentHash": "TlXQBinK35LpOPKHAqbLY4xlEen9TBafjs0V5KnA4wZsoQLQJiirCR4CbIXvOH8NzkW4YeJKP5P/Bnrodm0h9Q==", - "dependencies": { - "xunit.analyzers": "1.18.0", - "xunit.assert": "2.9.3", - "xunit.core": "[2.9.3]" - } - }, "xunit.runner.visualstudio": { "type": "Direct", "requested": "[3.0.2, )", "resolved": "3.0.2", "contentHash": "oXbusR6iPq0xlqoikjdLvzh+wQDkMv9If58myz9MEzldS4nIcp442Btgs2sWbYWV+caEluMe2pQCZ0hUZgPiow==" }, + "Argon": { + "type": "Transitive", + "resolved": "0.27.0", + "contentHash": "LtZKATYeTwDyYq1AXrgVU/ly+nI6GvE0GK1isJYFPQOnb2uHUxvDA+yh40QYaITGTLViXK7rbWhNKpbZ5pb9XA==" + }, + "Castle.Core": { + "type": "Transitive", + "resolved": "5.1.1", + "contentHash": "rpYtIczkzGpf+EkZgDr9CClTdemhsrwA/W5hMoPjLkRFnXzH44zDLoovXeKtmxb1ykXK9aJVODSpiJml8CTw2g==", + "dependencies": { + "System.Diagnostics.EventLog": "6.0.0" + } + }, + "DiffEngine": { + "type": "Transitive", + "resolved": "16.1.0", + "contentHash": "ImEFC6BN62paN0N7v8vrLY3x/LpfbJaJy5yDtL+/L2As6FI1npGJcFZwzz1A7pdDjIYPOXE91qv6BpgEUGjDkA==", + "dependencies": { + "EmptyFiles": "8.8.0", + "System.Management": "8.0.0" + } + }, + "EmptyFiles": { + "type": "Transitive", + "resolved": "8.8.0", + "contentHash": "d0pgc/vMyKgQ9T3qiiJBn1uYUSZ1/OShh6tySnNSkELRSgM4A4IOrpdQhLqwCkPwYvdJqzKuxQ6wn3MQAd4GNA==" + }, + "FSharp.Core": { + "type": "Transitive", + "resolved": "7.0.300", + "contentHash": "8vvItREJ1l5lcp3vBCSJ1mFevVAhR48I34DuF/EoUa7o1KlFpQpagyuZkVYMAsHPIjdp47ZxM9sI4eqeXaeWkA==" + }, "GraphQL.Client.Abstractions": { "type": "Transitive", "resolved": "6.0.0", @@ -192,6 +219,20 @@ "resolved": "13.0.1", "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==" }, + "Quibble": { + "type": "Transitive", + "resolved": "0.3.1", + "contentHash": "LD6bz2p+4O/BQnmD4mqFZrmdN/IjsPo1wUvfmcH46Q05ng+dyMLl3d2ylj0x412F4fpJEtm0Z3EaCAx4FqgNuQ==", + "dependencies": { + "FSharp.Core": "7.0.300", + "System.Text.Json": "7.0.3" + } + }, + "SimpleInfoName": { + "type": "Transitive", + "resolved": "3.1.0", + "contentHash": "j+ENh86NhxrgDc6T1ueqIR2QOdDkSJY2dbTFyPN/JvIXifB4GHAunlMw/x7P6m7XaXEHr3s+SMZfKBlmnmkO6g==" + }, "SQLitePCLRaw.bundle_e_sqlite3": { "type": "Transitive", "resolved": "2.1.4", @@ -222,11 +263,34 @@ "SQLitePCLRaw.core": "2.1.4" } }, + "System.CodeDom": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "WTlRjL6KWIMr/pAaq3rYqh0TJlzpouaQ/W1eelssHgtlwHAH25jXTkUphTYx9HaIIf7XA6qs/0+YhtLEQRkJ+Q==" + }, "System.ComponentModel.Annotations": { "type": "Transitive", "resolved": "4.5.0", "contentHash": "UxYQ3FGUOtzJ7LfSdnYSFd7+oEv6M8NgUatatIN2HxNtDdlcvFAf+VIq4Of9cDMJEJC0aSRv/x898RYhB4Yppg==" }, + "System.Diagnostics.EventLog": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "lcyUiXTsETK2ALsZrX+nWuHSIQeazhqPphLfaRxzdGaG93+0kELqpgEHtwWOlQe7+jSFnKwaCAgL4kjeZCQJnw==" + }, + "System.IO.Hashing": { + "type": "Transitive", + "resolved": "9.0.3", + "contentHash": "BrMGzDRLz410PE4qC8UeKeAc0hFRjBkiCUOLTwuod65NAjqg5tDNqYU7gP0A09taEXtecB+HJc1NNnnTjsKFAQ==" + }, + "System.Management": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "jrK22i5LRzxZCfGb+tGmke2VH7oE0DvcDlJ1HAKYU8cPmD8XnpUT0bYn2Gy98GEhGjtfbR/sxKTVb+dE770pfA==", + "dependencies": { + "System.CodeDom": "8.0.0" + } + }, "System.Memory": { "type": "Transitive", "resolved": "4.5.3", @@ -247,6 +311,30 @@ "resolved": "4.5.1", "contentHash": "Zh8t8oqolRaFa9vmOZfdQm/qKejdqz0J9kr7o2Fu0vPeoH3BL1EOXipKWwkWtLT1JPzjByrF19fGuFlNbmPpiw==" }, + "System.Text.Encodings.Web": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==" + }, + "System.Text.Json": { + "type": "Transitive", + "resolved": "8.0.4", + "contentHash": "bAkhgDJ88XTsqczoxEMliSrpijKZHhbJQldhAmObj/RbrN3sU5dcokuXmWJWsdQAhiMJ9bTayWsL1C9fbbCRhw==", + "dependencies": { + "System.Text.Encodings.Web": "8.0.0" + } + }, + "Verify": { + "type": "Transitive", + "resolved": "29.2.0", + "contentHash": "EhhwhXIeip9AJGWRPXh47NAUoiELnWzeBnAzFSl0+ryAfijTV1T+B4m6P6GbheWQ1CJ1cC1ZFLzgH276D5Bu3A==", + "dependencies": { + "Argon": "0.27.0", + "DiffEngine": "16.1.0", + "SimpleInfoName": "3.1.0", + "System.IO.Hashing": "9.0.3" + } + }, "xunit.abstractions": { "type": "Transitive", "resolved": "2.0.3", @@ -298,6 +386,18 @@ "speckle.sdk.dependencies": { "type": "Project" }, + "speckle.sdk.testing": { + "type": "Project", + "dependencies": { + "Microsoft.NET.Test.Sdk": "[17.13.0, )", + "Moq": "[4.20.72, )", + "Speckle.Sdk": "[1.0.0, )", + "Verify.Quibble": "[2.1.1, )", + "Verify.Xunit": "[29.2.0, )", + "xunit": "[2.9.3, )", + "xunit.runner.visualstudio": "[3.0.2, )" + } + }, "GraphQL.Client": { "type": "CentralTransitive", "requested": "[6.0.0, )", @@ -343,12 +443,58 @@ "Microsoft.Extensions.Options": "2.2.0" } }, + "Moq": { + "type": "CentralTransitive", + "requested": "[4.20.72, )", + "resolved": "4.20.72", + "contentHash": "EA55cjyNn8eTNWrgrdZJH5QLFp2L43oxl1tlkoYUKIE9pRwL784OWiTXeCV5ApS+AMYEAlt7Fo03A2XfouvHmQ==", + "dependencies": { + "Castle.Core": "5.1.1" + } + }, "Speckle.Newtonsoft.Json": { "type": "CentralTransitive", "requested": "[13.0.2, )", "resolved": "13.0.2", "contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA==" }, + "Verify.Quibble": { + "type": "CentralTransitive", + "requested": "[2.1.1, )", + "resolved": "2.1.1", + "contentHash": "Z8bVwFICa3Dog6Mcnx0wlrn4Y+CFpQXx1f+ijfLn6/v4q00q+jLm9Gu/nVyUFuc75cjn6ieI08UrqXKcR9fTYw==", + "dependencies": { + "Quibble": "0.3.1", + "System.Text.Json": "8.0.4", + "Verify": "26.1.1" + } + }, + "Verify.Xunit": { + "type": "CentralTransitive", + "requested": "[29.2.0, )", + "resolved": "29.2.0", + "contentHash": "MdcslVf40AzSA319ZHMzR+U4JqyquX28JFSrI9zA89yeZNaNcaSIb5PmE0XZ6p60Iy7eRYtnGEgSDimEUeXHZw==", + "dependencies": { + "Argon": "0.27.0", + "DiffEngine": "16.1.0", + "SimpleInfoName": "3.1.0", + "System.IO.Hashing": "9.0.3", + "Verify": "29.2.0", + "xunit.abstractions": "2.0.3", + "xunit.extensibility.execution": "2.9.3" + } + }, + "xunit": { + "type": "CentralTransitive", + "requested": "[2.9.3, )", + "resolved": "2.9.3", + "contentHash": "TlXQBinK35LpOPKHAqbLY4xlEen9TBafjs0V5KnA4wZsoQLQJiirCR4CbIXvOH8NzkW4YeJKP5P/Bnrodm0h9Q==", + "dependencies": { + "xunit.analyzers": "1.18.0", + "xunit.assert": "2.9.3", + "xunit.core": "[2.9.3]" + } + }, "xunit.assert": { "type": "CentralTransitive", "requested": "[2.9.3, )",