Compare commits

..

6 Commits

Author SHA1 Message Date
Jedd Morgan 00a6619cbe feat(api)!: Add model permission checks and deprecate canPublish (#434)
.NET Build and Publish / build (push) Has been cancelled
* Add permission checks and deprecate canPublish

* Fix tests

* How's this

* make tests more reliable

* lets test this first

* test

* This should speed up unit tests

* skip slow tests

* I HATE flaky tests
2026-01-27 16:35:48 +00:00
Jedd Morgan 49ef9917c4 Model Ingestion Version message (#427)
.NET Build and Publish / build (push) Has been cancelled
2026-01-26 16:03:16 +00:00
Jedd Morgan 94b0473157 MarkReceivedVersionInput clarification (#433) 2026-01-26 15:52:56 +00:00
Jedd Morgan 8071990dd5 deprecate file import api (#431) 2026-01-15 16:29:33 +00:00
Jedd Morgan 8c7dbc89aa update nullability of invitedBy (#432) 2026-01-15 14:21:40 +00:00
Jedd Morgan 676a3df153 Update docker-compose-internal.yml (#430) 2026-01-07 15:54:30 +00:00
47 changed files with 218 additions and 106 deletions
+1
View File
@@ -10,6 +10,7 @@
<File Path="Directory.Build.props" />
<File Path="Directory.Build.Targets" />
<File Path="Directory.Packages.props" />
<File Path="docker-compose-internal.yml" />
<File Path="docker-compose.yml" />
<File Path="global.json" />
<File Path="README.md" />
+1 -4
View File
@@ -97,10 +97,7 @@ services:
STRATEGY_LOCAL: "true"
POSTGRES_URL: "postgres"
POSTGRES_USER: "speckle"
POSTGRES_PASSWORD: "speckle"
POSTGRES_DB: "speckle"
POSTGRES_URL: 'postgres://speckle:speckle@postgres:5432/speckle'
ENABLE_MP: "false"
LOG_PRETTY: "true"
@@ -2,8 +2,10 @@
public record GenerateFileUploadUrlInput(string projectId, string fileName);
[Obsolete(FileImportInputBase.FILE_IMPORT_DEPRECATION_MESSAGE)]
public record StartFileImportInput(string projectId, string modelId, string fileId, string etag);
[Obsolete(FileImportInputBase.FILE_IMPORT_DEPRECATION_MESSAGE)]
public record FileImportResult(
double durationSeconds,
double downloadDurationSeconds,
@@ -14,14 +16,23 @@ public record FileImportResult(
public abstract class FileImportInputBase
{
internal const string FILE_IMPORT_DEPRECATION_MESSAGE =
"Part of the old API surface and will be removed in the future. Use the new ingestion API instead. Field will be deleted on June 1st, 2026";
[Obsolete(FileImportInputBase.FILE_IMPORT_DEPRECATION_MESSAGE)]
protected FileImportInputBase() { }
public required string projectId { get; init; }
public required string jobId { get; init; }
public required IReadOnlyCollection<string> warnings { get; init; }
[Obsolete(FileImportInputBase.FILE_IMPORT_DEPRECATION_MESSAGE)]
public required FileImportResult result { get; init; }
}
#pragma warning disable CA1822 //Mark members as static
[Obsolete(FILE_IMPORT_DEPRECATION_MESSAGE)]
public sealed class FileImportSuccessInput() : FileImportInputBase()
{
public const string TYPE_STATUS = "success";
@@ -29,6 +40,7 @@ public sealed class FileImportSuccessInput() : FileImportInputBase()
public string status => TYPE_STATUS;
}
[Obsolete(FILE_IMPORT_DEPRECATION_MESSAGE)]
public sealed class FileImportErrorInput() : FileImportInputBase()
{
public const string TYPE_STATUS = "error";
@@ -19,7 +19,12 @@ public record ModelIngestionCreateInput(
public record ModelIngestionUpdateInput(string ingestionId, string projectId, string progressMessage, double? progress);
public record ModelIngestionSuccessInput(string ingestionId, string projectId, string rootObjectId);
public record ModelIngestionSuccessInput(
string ingestionId,
string projectId,
string rootObjectId,
string? versionMessage
);
public record ModelIngestionFailedInput(
string ingestionId,
@@ -1,4 +1,6 @@
namespace Speckle.Sdk.Api.GraphQL.Inputs;
using Version = Speckle.Sdk.Api.GraphQL.Models.Version;
namespace Speckle.Sdk.Api.GraphQL.Inputs;
public record UpdateVersionInput(string versionId, string projectId, string? message);
@@ -16,6 +18,10 @@ public record CreateVersionInput(
IReadOnlyList<string>? parents = null
);
/// <param name="versionId"></param>
/// <param name="projectId"></param>
/// <param name="sourceApplication">IMPORTANT: this is meant to be the slug of the application that has done the receiving, not to be confused with <see cref="Version.sourceApplication"/></param>
/// <param name="message"></param>
public record MarkReceivedVersionInput(
string versionId,
string projectId,
@@ -0,0 +1,8 @@
namespace Speckle.Sdk.Api.GraphQL.Models;
public sealed class ModelPermissionChecks
{
public PermissionCheckResult canUpdate { get; init; }
public PermissionCheckResult canDelete { get; init; }
public PermissionCheckResult canCreateVersion { get; init; }
}
@@ -10,7 +10,7 @@ public sealed class PendingStreamCollaborator
public string projectName { get; init; }
public string title { get; init; }
public string role { get; init; }
public LimitedUser invitedBy { get; init; }
public LimitedUser? invitedBy { get; init; }
public LimitedUser? user { get; init; }
public string? token { get; init; }
}
@@ -5,5 +5,7 @@ public sealed class ProjectPermissionChecks
public PermissionCheckResult canCreateModel { get; init; }
public PermissionCheckResult canDelete { get; init; }
public PermissionCheckResult canLoad { get; init; }
[Obsolete("Use ModelPermissionChecks.CanCreateVersion instead", true)]
public PermissionCheckResult canPublish { get; init; }
}
@@ -397,11 +397,6 @@ public sealed class ActiveUserResource
authorized
message
}
canPublish {
code
authorized
message
}
}
}
}
@@ -29,8 +29,10 @@ public sealed class FileImportResource : IDisposable
/// <remarks>
/// Only use this if you are writing a file importer, that is responsible for
/// processing file import jobs.
/// Only works on servers version >=2.25.8
/// Only works on servers version >=2.25.8 but from 3.0.7 onwards has been deprecated and replaced by model ingestion api
/// see <see cref="ModelIngestionResource.Complete"/>
/// </remarks>
[Obsolete(FileImportInputBase.FILE_IMPORT_DEPRECATION_MESSAGE)]
public async Task<bool> FinishFileImportJob(FileImportInputBase input, CancellationToken cancellationToken)
{
//language=graphql
@@ -57,7 +59,11 @@ public sealed class FileImportResource : IDisposable
/// <param name="cancellationToken"></param>
/// <returns></returns>
/// <inheritdoc cref="ISpeckleGraphQLClient.ExecuteGraphQLRequest{T}"/>
/// <remarks>Only works on servers version >=2.25.8</remarks>
/// <remarks>
/// Only works on servers version >=2.25.8 but from 3.0.7 onwards has been deprecated and replaced by model ingestion api
/// see <see cref="ModelIngestionResource.StartProcessing"/>
/// </remarks>
[Obsolete(FileImportInputBase.FILE_IMPORT_DEPRECATION_MESSAGE)]
public async Task<FileImport> StartFileImportJob(
StartFileImportInput input,
CancellationToken cancellationToken = default
@@ -312,4 +312,51 @@ public sealed class ModelResource
return res.data.data;
}
/// <param name="projectId"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
/// <inheritdoc cref="ISpeckleGraphQLClient.ExecuteGraphQLRequest{T}"/>
public async Task<ModelPermissionChecks> GetPermissions(
string projectId,
string modelId,
CancellationToken cancellationToken = default
)
{
//language=graphql
const string QUERY = """
query ModelPermissions($projectId: String!, $modelId: String!) {
data:project(id: $projectId) {
data:model(id: $modelId) {
data:permissions {
canUpdate {
authorized
code
message
}
canDelete {
authorized
code
message
}
canCreateVersion {
authorized
code
message
}
}
}
}
}
""";
GraphQLRequest request = new() { Query = QUERY, Variables = new { projectId, modelId } };
var response = await _client
.ExecuteGraphQLRequest<RequiredResponse<RequiredResponse<RequiredResponse<ModelPermissionChecks>>>>(
request,
cancellationToken
)
.ConfigureAwait(false);
return response.data.data.data;
}
}
+16 -1
View File
@@ -140,7 +140,22 @@ internal static class TypeLoader
return typeof(Base);
}
//Don't use unless you're testing
/// <summary>
/// For testing purposes only
/// </summary>
internal static void ReInitialize(params Assembly[] assemblies)
{
lock (s_availableTypes)
{
Reset();
Load(assemblies);
s_initialized = true;
}
}
/// <summary>
/// For testing purposes only
/// </summary>
public static void Reset()
{
s_availableTypes = new();
@@ -184,7 +184,7 @@ public class SerializationTests
idToBase.Count.Should().Be(count);
}
[Theory]
[Theory(Skip = "Takes too long")]
[InlineData(1)]
[InlineData(4)]
public async Task Roundtrip_Test_New(int concurrency)
@@ -1,8 +0,0 @@
{
"Type": "AggregateException",
"InnerException": {
"Data": {},
"Message": "NOT_FOUND_ERROR: Model ingestion not found",
"Type": "SpeckleGraphQLException"
}
}
@@ -1,8 +0,0 @@
{
"Type": "AggregateException",
"InnerException": {
"Data": {},
"Message": "STREAM_NOT_FOUND: Project not found",
"Type": "SpeckleGraphQLStreamNotFoundException"
}
}
@@ -1,8 +0,0 @@
{
"Type": "AggregateException",
"InnerException": {
"Data": {},
"Message": "NOT_FOUND_ERROR: Model ingestion not found",
"Type": "SpeckleGraphQLException"
}
}
@@ -1,10 +1,7 @@
using System.Reflection;
using Speckle.Sdk.Api;
using Speckle.Sdk.Api.GraphQL.Inputs;
using Speckle.Sdk.Api.GraphQL.Models;
using Speckle.Sdk.Api.GraphQL.Resources;
using Speckle.Sdk.Host;
using Speckle.Sdk.Models;
namespace Speckle.Sdk.Tests.Integration.API.GraphQL.Resources;
@@ -20,9 +17,6 @@ public sealed class ModelIngestionResourceExceptionalTests : IAsyncLifetime
public async Task InitializeAsync()
{
TypeLoader.Reset();
TypeLoader.Initialize(typeof(Base).Assembly, Assembly.GetExecutingAssembly());
_testUser = await Fixtures.SeedUserWithClient();
_project = await _testUser.Project.Create(new("Test project", "", null));
_model = await _testUser.Model.Create(new("Test Model 1", "", _project.id));
@@ -42,7 +36,8 @@ public sealed class ModelIngestionResourceExceptionalTests : IAsyncLifetime
{
_ = await Sut.Create(createInput);
});
await Verify(ex);
Assert.Single(ex.InnerExceptions);
Assert.All(ex.InnerExceptions, item => Assert.IsType<SpeckleGraphQLStreamNotFoundException>(item));
}
[Fact]
@@ -54,7 +49,8 @@ public sealed class ModelIngestionResourceExceptionalTests : IAsyncLifetime
{
_ = await Sut.UpdateProgress(updateInput);
});
await Verify(ex);
Assert.Single(ex.InnerExceptions);
Assert.All(ex.InnerExceptions, item => Assert.IsType<SpeckleGraphQLException>(item));
}
[Fact]
@@ -69,6 +65,7 @@ public sealed class ModelIngestionResourceExceptionalTests : IAsyncLifetime
{
_ = await Sut.FailWithCancel(input);
});
await Verify(ex);
Assert.Single(ex.InnerExceptions);
Assert.All(ex.InnerExceptions, item => Assert.IsType<SpeckleGraphQLException>(item));
}
}
@@ -1,11 +1,9 @@
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using Speckle.Sdk.Api;
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 Speckle.Sdk.Host;
using Speckle.Sdk.Models;
using Speckle.Sdk.Transports;
using Version = Speckle.Sdk.Api.GraphQL.Models.Version;
@@ -25,8 +23,6 @@ public sealed class ModelIngestionResourceTests : IAsyncLifetime
public async Task InitializeAsync()
{
TypeLoader.Reset();
TypeLoader.Initialize(typeof(Base).Assembly, Assembly.GetExecutingAssembly());
var serviceProvider = TestServiceSetup.GetServiceProvider();
_operations = serviceProvider.GetRequiredService<IOperations>();
@@ -130,7 +126,7 @@ public sealed class ModelIngestionResourceTests : IAsyncLifetime
new(true, true)
);
ModelIngestionSuccessInput finish = new(ingest.id, _project.id, sendResult.RootId);
ModelIngestionSuccessInput finish = new(ingest.id, _project.id, sendResult.RootId, "yay!");
string versionId = await Sut.Complete(finish);
Version version = await _testUser.Version.Get(versionId, _project.id);
Assert.Equal(version.id, versionId);
@@ -1,5 +1,6 @@
using FluentAssertions;
using Speckle.Sdk.Api;
using Speckle.Sdk.Api.GraphQL.Enums;
using Speckle.Sdk.Api.GraphQL.Inputs;
using Speckle.Sdk.Api.GraphQL.Models;
using Speckle.Sdk.Api.GraphQL.Resources;
@@ -17,7 +18,7 @@ public class ModelResourceTests : IAsyncLifetime
{
// Runs instead of [SetUp] in NUnit
_testUser = await Fixtures.SeedUserWithClient();
_project = await _testUser.Project.Create(new("Test project", "", null));
_project = await _testUser.Project.Create(new("Test project", "", ProjectVisibility.Public));
_model = await _testUser.Model.Create(new("Test Model", "", _project.id));
}
@@ -123,4 +124,21 @@ public class ModelResourceTests : IAsyncLifetime
var delEx = await FluentActions.Invoking(() => Sut.Delete(input)).Should().ThrowAsync<AggregateException>();
getEx.WithInnerExceptionExactly<SpeckleGraphQLException>();
}
[Fact]
public async Task TestUserHasModelPermissions()
{
var ownerResult = await Sut.GetPermissions(_project.id, _model.id);
ownerResult.canUpdate.authorized.Should().Be(true);
ownerResult.canCreateVersion.authorized.Should().Be(true);
ownerResult.canDelete.authorized.Should().Be(true);
// Test with another user
var guest = await Fixtures.SeedUserWithClient();
var guestResult = await guest.Model.GetPermissions(_project.id, _model.id);
guestResult.canUpdate.authorized.Should().Be(false);
guestResult.canCreateVersion.authorized.Should().Be(false);
guestResult.canDelete.authorized.Should().Be(false);
}
}
@@ -103,8 +103,30 @@ public class ProjectResourceTests
[Fact]
public async Task TestUserHasProjectPermissions()
{
var res = await Sut.GetPermissions(_testProject.id);
var privateProject = await _testUser.Project.Create(
new ProjectCreateInput("asdfasdf", "desc", ProjectVisibility.Private)
);
var resp = await Sut.GetPermissions(privateProject.id);
resp.canCreateModel.authorized.Should().Be(true);
resp.canDelete.authorized.Should().Be(true);
resp.canLoad.authorized.Should().Be(true);
var publicProject = await _testUser.Project.Create(
new ProjectCreateInput("asdfasdf", "desc", ProjectVisibility.Public)
);
var res = await Sut.GetPermissions(publicProject.id);
res.canCreateModel.authorized.Should().Be(true);
res.canDelete.authorized.Should().Be(true);
res.canLoad.authorized.Should().Be(true);
// Test with another user
var guest = await Fixtures.SeedUserWithClient();
var guestResult = await guest.Project.GetPermissions(publicProject.id);
guestResult.canCreateModel.authorized.Should().Be(false);
guestResult.canDelete.authorized.Should().Be(false);
guestResult.canLoad.authorized.Should().Be(false);
}
}
@@ -13,9 +13,9 @@ public class SubscriptionResourceTests : IAsyncLifetime
#if DEBUG
private const int WAIT_PERIOD = 4000; // WSL is slow AF, so for local runs, we're being extra generous
#else
private const int WAIT_PERIOD = 400; // For CI runs, a much smaller wait time is acceptable
private const int WAIT_PERIOD = 500; // For CI runs, a much smaller wait time is acceptable
#endif
private const int TIMEOUT = WAIT_PERIOD + WAIT_PERIOD + 400;
private const int TIMEOUT = WAIT_PERIOD + WAIT_PERIOD + 500;
private IClient _testUser;
private Project _testProject;
private Model _testModel;
@@ -17,6 +17,11 @@ using Version = Speckle.Sdk.Api.GraphQL.Models.Version;
[assembly: AssemblyTrait("Category", "Integration")]
#if DEBUG
[assembly: CollectionBehavior(MaxParallelThreads = 8)]
#endif
namespace Speckle.Sdk.Tests.Integration;
public static class Fixtures
@@ -1,8 +1,6 @@
using System.Reflection;
using FluentAssertions;
using FluentAssertions;
using Microsoft.Extensions.DependencyInjection;
using Speckle.Sdk.Api;
using Speckle.Sdk.Host;
using Speckle.Sdk.Models;
using Speckle.Sdk.Transports;
@@ -16,8 +14,7 @@ public class MemoryTransportTests : IDisposable
public MemoryTransportTests()
{
CleanData();
TypeLoader.Reset();
TypeLoader.Initialize(typeof(Base).Assembly, Assembly.GetExecutingAssembly());
var serviceProvider = TestServiceSetup.GetServiceProvider();
_operations = serviceProvider.GetRequiredService<IOperations>();
}
@@ -1,11 +1,8 @@
using System.Reflection;
using System.Text;
using System.Text;
using Microsoft.Extensions.DependencyInjection;
using Speckle.Sdk.Api;
using Speckle.Sdk.Api.GraphQL.Enums;
using Speckle.Sdk.Api.GraphQL.Models;
using Speckle.Sdk.Host;
using Speckle.Sdk.Models;
namespace Speckle.Sdk.Tests.Integration;
@@ -19,8 +16,6 @@ public sealed class SendReceiveTests : IAsyncLifetime
public async Task InitializeAsync()
{
TypeLoader.Reset();
TypeLoader.Initialize(typeof(Base).Assembly, Assembly.GetExecutingAssembly());
var serviceProvider = TestServiceSetup.GetServiceProvider();
_operations = serviceProvider.GetRequiredService<IOperations>();
ClearCache();
@@ -10,14 +10,14 @@ using Speckle.Sdk.Transports;
namespace Speckle.Sdk.Tests.Unit.Api.Operations;
[Collection(nameof(RequiresTypeLoaderCollection))]
public class Closures
{
private readonly IOperations _operations;
public Closures()
{
TypeLoader.Reset();
TypeLoader.Initialize(typeof(Base).Assembly, typeof(TableLegFixture).Assembly);
TypeLoader.ReInitialize(typeof(Base).Assembly, typeof(TableLegFixture).Assembly);
var serviceProvider = TestServiceSetup.GetServiceProvider();
_operations = serviceProvider.GetRequiredService<IOperations>();
}
@@ -7,6 +7,7 @@ using Speckle.Sdk.Transports;
namespace Speckle.Sdk.Tests.Unit.Api.Operations;
[Collection(nameof(RequiresTypeLoaderCollection))]
public sealed partial class OperationsReceiveTests : IDisposable
{
private static readonly Base[] s_testObjects;
@@ -44,8 +45,7 @@ public sealed partial class OperationsReceiveTests : IDisposable
private static void Reset()
{
TypeLoader.Reset();
TypeLoader.Initialize(typeof(Base).Assembly, Assembly.GetExecutingAssembly());
TypeLoader.ReInitialize(typeof(Base).Assembly, Assembly.GetExecutingAssembly());
}
public static IEnumerable<object[]> TestCases()
@@ -7,14 +7,14 @@ using Speckle.Sdk.Transports;
namespace Speckle.Sdk.Tests.Unit.Api.Operations;
[Collection(nameof(RequiresTypeLoaderCollection))]
public class SendObjectReferences
{
private readonly IOperations _operations;
public SendObjectReferences()
{
TypeLoader.Reset();
TypeLoader.Initialize(typeof(Base).Assembly, typeof(DataChunk).Assembly);
TypeLoader.ReInitialize(typeof(Base).Assembly, typeof(DataChunk).Assembly);
var serviceProvider = TestServiceSetup.GetServiceProvider();
_operations = serviceProvider.GetRequiredService<IOperations>();
}
@@ -9,14 +9,14 @@ using Speckle.Sdk.Transports;
namespace Speckle.Sdk.Tests.Unit.Api.Operations;
[Collection(nameof(RequiresTypeLoaderCollection))]
public sealed class SendReceiveLocal : IDisposable
{
private readonly IOperations _operations;
public SendReceiveLocal()
{
TypeLoader.Reset();
TypeLoader.Initialize(typeof(Base).Assembly, typeof(Point).Assembly);
TypeLoader.ReInitialize(typeof(Base).Assembly, typeof(Point).Assembly);
var serviceProvider = TestServiceSetup.GetServiceProvider();
_operations = serviceProvider.GetRequiredService<IOperations>();
}
@@ -9,14 +9,14 @@ using Point = Speckle.Sdk.Tests.Unit.Host.Point;
namespace Speckle.Sdk.Tests.Unit.Api.Operations;
[Collection(nameof(RequiresTypeLoaderCollection))]
public class ObjectSerialization
{
private readonly IOperations _operations;
public ObjectSerialization()
{
TypeLoader.Reset();
TypeLoader.Initialize(typeof(Base).Assembly, typeof(DataChunk).Assembly, typeof(ColorMock).Assembly);
TypeLoader.ReInitialize(typeof(Base).Assembly, typeof(DataChunk).Assembly, typeof(ColorMock).Assembly);
var serviceProvider = TestServiceSetup.GetServiceProvider();
_operations = serviceProvider.GetRequiredService<IOperations>();
}
+1 -1
View File
@@ -1 +1 @@
[assembly: CollectionBehavior(DisableTestParallelization = true)]
[assembly: CollectionBehavior()]
@@ -0,0 +1,7 @@
namespace Speckle.Sdk.Tests.Unit;
[CollectionDefinition(nameof(RequiresTypeLoaderCollection), DisableParallelization = true)]
public class RequiresTypeLoaderCollection;
[CollectionDefinition(nameof(RequiresSqLiteAccountDb), DisableParallelization = true)]
public class RequiresSqLiteAccountDb;
@@ -9,6 +9,7 @@ using Speckle.Sdk.Testing;
namespace Speckle.Sdk.Tests.Unit.Credentials;
[Collection(nameof(RequiresSqLiteAccountDb))]
public sealed class AccountManagerTests : MoqTest
{
private class TestAccountFactory : IAccountFactory
@@ -5,6 +5,7 @@ using Speckle.Sdk.Credentials;
namespace Speckle.Sdk.Tests.Unit.Credentials;
[Collection(nameof(RequiresSqLiteAccountDb))]
public class AccountServerMigrationTests : IDisposable
{
private readonly List<Account> _accountsToCleanUp = [];
@@ -5,6 +5,7 @@ using Speckle.Sdk.Credentials;
namespace Speckle.Sdk.Tests.Unit.Credentials;
[Collection(nameof(RequiresSqLiteAccountDb))]
public class CredentialInfrastructure : IDisposable
{
private readonly IAccountManager _accountManager;
@@ -5,12 +5,12 @@ using Speckle.Sdk.Models;
namespace Speckle.Sdk.Tests.Unit.Models;
[Collection(nameof(RequiresTypeLoaderCollection))]
public class BaseTests
{
public BaseTests()
{
TypeLoader.Reset();
TypeLoader.Initialize(typeof(Base).Assembly, typeof(BaseTests).Assembly);
TypeLoader.ReInitialize(typeof(Base).Assembly, typeof(BaseTests).Assembly);
}
[Fact]
@@ -5,12 +5,12 @@ using Speckle.Sdk.Models;
namespace Speckle.Sdk.Tests.Unit.Models;
[Collection(nameof(RequiresTypeLoaderCollection))]
public class DynamicBaseTests
{
public DynamicBaseTests()
{
TypeLoader.Reset();
TypeLoader.Initialize(typeof(Base).Assembly, typeof(BaseTests).Assembly);
TypeLoader.ReInitialize(typeof(Base).Assembly, typeof(BaseTests).Assembly);
}
[Fact]
@@ -6,12 +6,12 @@ using Speckle.Sdk.Models.Extensions;
namespace Speckle.Sdk.Tests.Unit.Models.Extensions;
[Collection(nameof(RequiresTypeLoaderCollection))]
public class BaseExtensionsTests
{
public BaseExtensionsTests()
{
TypeLoader.Reset();
TypeLoader.Initialize(typeof(Base).Assembly, typeof(TestBase).Assembly);
TypeLoader.ReInitialize(typeof(Base).Assembly, typeof(TestBase).Assembly);
}
[Theory]
@@ -5,6 +5,7 @@ using Speckle.Sdk.Models.Extensions;
namespace Speckle.Sdk.Tests.Unit.Models.Extensions;
[Collection(nameof(RequiresTypeLoaderCollection))]
public class DisplayValueTests
{
private const string PAYLOAD = "This is my payload";
@@ -17,8 +18,7 @@ public class DisplayValueTests
private static void Reset()
{
TypeLoader.Reset();
TypeLoader.Initialize(typeof(Base).Assembly);
TypeLoader.ReInitialize(typeof(Base).Assembly);
}
[Fact]
@@ -6,12 +6,12 @@ using Speckle.Sdk.Models.GraphTraversal;
namespace Speckle.Sdk.Tests.Unit.Models.GraphTraversal;
[Collection(nameof(RequiresTypeLoaderCollection))]
public class GraphTraversalTests
{
public GraphTraversalTests()
{
TypeLoader.Reset();
TypeLoader.Initialize(typeof(Base).Assembly, typeof(TraversalMock).Assembly);
TypeLoader.ReInitialize(typeof(Base).Assembly, typeof(TraversalMock).Assembly);
}
private static IEnumerable<TraversalContext> Traverse(Base testCase, params ITraversalRule[] rules)
@@ -6,13 +6,12 @@ using Speckle.Sdk.Tests.Unit.Host;
namespace Speckle.Sdk.Tests.Unit.Models;
// Removed [TestFixture] and [TestOf] annotations as they are NUnit specific
[Collection(nameof(RequiresTypeLoaderCollection))]
public class Hashing
{
public Hashing()
{
TypeLoader.Reset();
TypeLoader.Initialize(typeof(Base).Assembly, typeof(DiningTable).Assembly);
TypeLoader.ReInitialize(typeof(Base).Assembly, typeof(DiningTable).Assembly);
}
[Fact(DisplayName = "Checks that hashing (as represented by object IDs) actually works.")]
@@ -5,13 +5,13 @@ using Speckle.Sdk.Tests.Unit.Models.TestModels;
namespace Speckle.Sdk.Tests.Unit.Models
{
[Collection(nameof(RequiresTypeLoaderCollection))]
public class SpeckleTypeTests
{
public SpeckleTypeTests()
{
// Setup logic during test class initialization
TypeLoader.Reset();
TypeLoader.Initialize(typeof(Base).Assembly, typeof(Foo).Assembly);
TypeLoader.ReInitialize(typeof(Base).Assembly, typeof(Foo).Assembly);
}
[Theory]
@@ -7,13 +7,13 @@ using Speckle.Sdk.Transports;
namespace Speckle.Sdk.Tests.Unit.Serialisation;
[Collection(nameof(RequiresTypeLoaderCollection))]
public class ChunkingTests
{
public static IEnumerable<object[]> TestCases()
{
// Initialize type loader
TypeLoader.Reset();
TypeLoader.Initialize(typeof(Base).Assembly, typeof(IgnoreTest).Assembly);
TypeLoader.ReInitialize(typeof(Base).Assembly, typeof(IgnoreTest).Assembly);
// Return test data as a collection of objects for xUnit
yield return [CreateDynamicTestCase(10, 100), 10];
@@ -12,12 +12,12 @@ namespace Speckle.Sdk.Tests.Unit.Serialisation;
/// Tests that the <see cref="JsonIgnoreAttribute"/> leads to properties being ignored both from the final JSON output,
/// But also from the id calculation
/// </summary>
[Collection(nameof(RequiresTypeLoaderCollection))]
public sealed class JsonIgnoreRespected
{
public JsonIgnoreRespected()
{
TypeLoader.Reset();
TypeLoader.Initialize(typeof(Base).Assembly, typeof(IgnoreTest).Assembly);
TypeLoader.ReInitialize(typeof(Base).Assembly, typeof(IgnoreTest).Assembly);
}
public static IEnumerable<object[]> IgnoredTestCases()
@@ -5,13 +5,13 @@ using Speckle.Sdk.Serialisation.Deprecated;
namespace Speckle.Sdk.Tests.Unit.Serialisation
{
[Collection(nameof(RequiresTypeLoaderCollection))]
public class TypeLoaderTests
{
// Constructor replaces the [SetUp] functionality in NUnit
public TypeLoaderTests()
{
TypeLoader.Reset();
TypeLoader.Initialize(typeof(Base).Assembly, typeof(MySpeckleBase).Assembly);
TypeLoader.ReInitialize(typeof(Base).Assembly, typeof(MySpeckleBase).Assembly);
}
[Fact] // Replaces [Test]
@@ -14,6 +14,7 @@ namespace Speckle.Sdk.Tests.Unit.Serialisation;
/// This doesn't guarantee things work this way for SpecklePy
/// Nor does it encompass other tricks (like deserialize callback, or computed json ignored properties)
/// </summary>
[Collection(nameof(RequiresTypeLoaderCollection))]
public class SerializerBreakingChanges : PrimitiveTestFixture
{
private readonly IOperations _operations;
@@ -21,8 +22,7 @@ public class SerializerBreakingChanges : PrimitiveTestFixture
// xUnit does not support a Setup method; instead, you can use the constructor for initialization.
public SerializerBreakingChanges()
{
TypeLoader.Reset();
TypeLoader.Initialize(typeof(Base).Assembly, typeof(Point).Assembly);
TypeLoader.ReInitialize(typeof(Base).Assembly, typeof(Point).Assembly);
var serviceProvider = TestServiceSetup.GetServiceProvider();
_operations = serviceProvider.GetRequiredService<IOperations>();
}
@@ -9,14 +9,14 @@ using Matrix4x4 = Speckle.DoubleNumerics.Matrix4x4;
namespace Speckle.Sdk.Tests.Unit.Serialisation;
[Collection(nameof(RequiresTypeLoaderCollection))]
public class SerializerNonBreakingChanges : PrimitiveTestFixture
{
private readonly IOperations _operations;
public SerializerNonBreakingChanges()
{
TypeLoader.Reset();
TypeLoader.Initialize(typeof(StringValueMock).Assembly);
TypeLoader.ReInitialize(typeof(StringValueMock).Assembly);
var serviceProvider = TestServiceSetup.GetServiceProvider();
_operations = serviceProvider.GetRequiredService<IOperations>();
}
@@ -1,17 +1,20 @@
using FluentAssertions;
using Microsoft.Extensions.DependencyInjection;
using Speckle.Sdk.Api;
using Speckle.Sdk.Host;
using Speckle.Sdk.Models;
using Speckle.Sdk.Tests.Unit.Host;
namespace Speckle.Sdk.Tests.Unit.Serialisation;
[Collection(nameof(RequiresTypeLoaderCollection))]
public class SimpleRoundTripTests
{
private readonly IOperations _operations;
public SimpleRoundTripTests()
{
TypeLoader.ReInitialize(typeof(DiningTable).Assembly);
var serviceProvider = TestServiceSetup.GetServiceProvider();
_operations = serviceProvider.GetRequiredService<IOperations>();
}