Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fdc0842b03 | |||
| 23d5dd44bc |
@@ -2,20 +2,15 @@ name: .NET Build and Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: ["3.*.*"]
|
||||
tags: ["3.*"]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: 'nuget.org'
|
||||
permissions:
|
||||
id-token: write # enable GitHub OIDC token issuance for this job
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
@@ -25,7 +20,7 @@ jobs:
|
||||
with:
|
||||
path: ~/.nuget/packages
|
||||
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
|
||||
|
||||
|
||||
- id: set-version
|
||||
name: Set version to output
|
||||
run: |
|
||||
@@ -42,24 +37,18 @@ jobs:
|
||||
|
||||
echo $SEMVER
|
||||
echo $FILE_VERSION
|
||||
|
||||
|
||||
- name: 🔫 Build and Pack
|
||||
run: ./build.sh pack
|
||||
env:
|
||||
SEMVER: ${{ steps.set-version.outputs.SEMVER }}
|
||||
FILE_VERSION: ${{ steps.set-version.outputs.FILE_VERSION }}
|
||||
|
||||
|
||||
- name: Upload coverage reports to Codecov with GitHub Action
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
files: tests/**/coverage.xml
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
- name: NuGet login (OIDC → temp API key)
|
||||
uses: NuGet/login@v1
|
||||
id: login
|
||||
with:
|
||||
user: ${{ secrets.NUGET_USER }}
|
||||
|
||||
- name: Push to nuget.org
|
||||
run: dotnet nuget push output/*.nupkg --source "https://api.nuget.org/v3/index.json" --api-key ${{steps.login.outputs.NUGET_API_KEY}}
|
||||
run: dotnet nuget push output/*.nupkg --source "https://api.nuget.org/v3/index.json" --api-key ${{secrets.CONNECTORS_NUGET_TOKEN }} --skip-duplicate
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<PropertyGroup Condition="'$(IsTestProject)' == 'true'">
|
||||
<NoWarn>
|
||||
<!-- Things we need to test -->
|
||||
CS0618;CA1034;CA2201;CA1051;CA1040;CA1724;CA1065;
|
||||
CS0618;CA1034;CA2201;CA1051;CA1040;CA1724;
|
||||
IDE0044;IDE0130;CA1508;
|
||||
<!-- Analysers that provide no tangeable value to a test project -->
|
||||
CA5394;CA2007;CA1852;CA1819;CA1711;CA1063;CA1816;CA2234;CS8618;CA1054;CA1810;CA2208;CA1019;CA1831;
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
using Speckle.Objects.Geometry;
|
||||
using Speckle.Sdk.Models;
|
||||
|
||||
namespace Speckle.Objects.Other;
|
||||
|
||||
/// <summary>
|
||||
/// Camera class to represent a perspective camera for a 3D view.
|
||||
/// </summary>
|
||||
/// <remarks>Assumes a Z-up, right-handed convention for orientation vectors</remarks>
|
||||
[SpeckleType("Objects.Other.Camera")]
|
||||
public class Camera : Base
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the view that is created by this camera
|
||||
/// </summary>
|
||||
public required string name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The location of the camera
|
||||
/// </summary>
|
||||
public required Point position { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The unit up vector of the camera
|
||||
/// </summary>
|
||||
public required Vector up { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The unit forward vector of the camera
|
||||
/// </summary>
|
||||
public required Vector forward { get; set; }
|
||||
}
|
||||
@@ -35,6 +35,6 @@ public class RenderMaterial : Base
|
||||
public Color emissiveColor
|
||||
{
|
||||
get => Color.FromArgb(emissive);
|
||||
set => emissive = value.ToArgb();
|
||||
set => diffuse = value.ToArgb();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ public sealed class Comment
|
||||
public string rawText { get; init; }
|
||||
public ResourceCollection<Comment> replies { get; init; }
|
||||
public CommentReplyAuthorCollection replyAuthors { get; init; }
|
||||
public List<ResourceIdentifier> resources { get; init; } //todo: add resourceIds/baseResourceIds
|
||||
public List<ResourceIdentifier> resources { get; init; }
|
||||
public string? screenshot { get; init; }
|
||||
public DateTime updatedAt { get; init; }
|
||||
public DateTime? viewedAt { get; init; }
|
||||
|
||||
@@ -2,7 +2,6 @@ using Microsoft.Extensions.Logging;
|
||||
using Speckle.Sdk.Logging;
|
||||
using Speckle.Sdk.Models;
|
||||
using Speckle.Sdk.Serialisation;
|
||||
using Speckle.Sdk.Serialisation.V2.Receive;
|
||||
using Speckle.Sdk.Transports;
|
||||
|
||||
namespace Speckle.Sdk.Api;
|
||||
@@ -16,7 +15,6 @@ public partial class Operations
|
||||
/// <exception cref="ArgumentException">No transports were specified</exception>
|
||||
/// <exception cref="ArgumentNullException">The <paramref name="objectId"/> was <see langword="null"/></exception>
|
||||
/// <exception cref="SpeckleException">Serialization or Send operation was unsuccessful</exception>
|
||||
/// <exception cref="HttpRequestException">HTTP layer errors</exception>
|
||||
/// <exception cref="OperationCanceledException">The <paramref name="cancellationToken"/> requested cancellation</exception>
|
||||
public async Task<Base> Receive2(
|
||||
Uri url,
|
||||
@@ -24,8 +22,7 @@ public partial class Operations
|
||||
string objectId,
|
||||
string? authorizationToken,
|
||||
IProgress<ProgressArgs>? onProgressAction,
|
||||
CancellationToken cancellationToken,
|
||||
DeserializeProcessOptions? options = null
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
using var receiveActivity = activityFactory.Start("Operations.Receive");
|
||||
@@ -39,8 +36,7 @@ public partial class Operations
|
||||
streamId,
|
||||
authorizationToken,
|
||||
onProgressAction,
|
||||
cancellationToken,
|
||||
options
|
||||
cancellationToken
|
||||
);
|
||||
try
|
||||
{
|
||||
@@ -48,11 +44,6 @@ public partial class Operations
|
||||
receiveActivity?.SetStatus(SdkActivityStatusCode.Ok);
|
||||
return result;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
//this is handled by the caller
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
receiveActivity?.SetStatus(SdkActivityStatusCode.Error);
|
||||
|
||||
@@ -25,8 +25,7 @@ public partial class Operations
|
||||
string? authorizationToken,
|
||||
Base value,
|
||||
IProgress<ProgressArgs>? onProgressAction,
|
||||
CancellationToken cancellationToken,
|
||||
SerializeProcessOptions? options = null
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
using var receiveActivity = activityFactory.Start("Operations.Send");
|
||||
@@ -39,8 +38,7 @@ public partial class Operations
|
||||
streamId,
|
||||
authorizationToken,
|
||||
onProgressAction,
|
||||
cancellationToken,
|
||||
options
|
||||
cancellationToken
|
||||
);
|
||||
try
|
||||
{
|
||||
|
||||
@@ -9,8 +9,6 @@ public static class SpecklePathProvider
|
||||
{
|
||||
private const string APPLICATION_NAME = "Speckle";
|
||||
|
||||
private const string LOG_FOLDER_NAME = "Logs";
|
||||
|
||||
private const string BLOB_FOLDER_NAME = "Blobs";
|
||||
|
||||
private const string ACCOUNTS_FOLDER_NAME = "Accounts";
|
||||
@@ -45,7 +43,7 @@ public static class SpecklePathProvider
|
||||
/// <see cref="Environment.SpecialFolder.ApplicationData"/> path usually maps to
|
||||
/// <ul>
|
||||
/// <li>win: <c>%appdata%/</c></li>
|
||||
/// <li>MacOS: <c>~/Library/Application Support</c></li>
|
||||
/// <li>MacOS: <c>~/.config/</c></li>
|
||||
/// <li>Linux: <c>~/.config/</c></li>
|
||||
/// </ul>
|
||||
/// </remarks>
|
||||
@@ -59,18 +57,29 @@ public static class SpecklePathProvider
|
||||
return pathOverride;
|
||||
}
|
||||
|
||||
// on desktop linux and macos we use the appdata.
|
||||
// but we might not have write access to the disk
|
||||
// so the catch falls back to the user profile
|
||||
try
|
||||
{
|
||||
return Environment.GetFolderPath(
|
||||
Environment.SpecialFolder.ApplicationData,
|
||||
// It's not a given that the folder is already there on all OS-es, so we'll create it
|
||||
// if the folder doesn't exist, we get back an empty string on OSX,
|
||||
// which in turn, breaks other stuff down the line.
|
||||
// passing in the Create option ensures that this directory exists,
|
||||
// which is not a given on all OS-es.
|
||||
Environment.SpecialFolderOption.Create
|
||||
);
|
||||
}
|
||||
catch (PlatformNotSupportedException)
|
||||
catch (SystemException ex) when (ex is PlatformNotSupportedException or ArgumentException)
|
||||
{
|
||||
// We might not have write access to the disk to create the folder,
|
||||
// so we'll fall back to the user profile
|
||||
//Adding this log just so we confidently know which Exception type to catch here.
|
||||
// TODO: Must re-add log call when (and if) this get's made as a service
|
||||
//SpeckleLog.Logger.Warning(ex, "Falling back to user profile path");
|
||||
|
||||
// on server linux, there might not be a user setup, things can run under root
|
||||
// in that case, the appdata variable is most probably not set up
|
||||
// we fall back to the value of the home folder
|
||||
return Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
|
||||
}
|
||||
}
|
||||
@@ -87,7 +96,4 @@ public static class SpecklePathProvider
|
||||
Directory.CreateDirectory(path);
|
||||
return path;
|
||||
}
|
||||
|
||||
public static string LogFolderPath(string applicationAndVersion) =>
|
||||
EnsureFolderExists(UserSpeckleFolderPath, LOG_FOLDER_NAME, applicationAndVersion);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ public class MemoryServerObjectManager(ConcurrentDictionary<string, string> obje
|
||||
{
|
||||
public virtual async IAsyncEnumerable<(string, string)> DownloadObjects(
|
||||
IReadOnlyCollection<string> objectIds,
|
||||
string? attributeMask,
|
||||
IProgress<ProgressArgs>? progress,
|
||||
[EnumeratorCancellation] CancellationToken cancellationToken
|
||||
)
|
||||
|
||||
@@ -10,7 +10,7 @@ using Speckle.Sdk.Transports;
|
||||
namespace Speckle.Sdk.Serialisation.V2.Receive;
|
||||
|
||||
public record DeserializeProcessOptions(
|
||||
bool SkipCache = false, //TODO: This appears to be bugged when set to `true`, `LoadId` depends on sqlite
|
||||
bool SkipCache = false,
|
||||
bool ThrowOnMissingReferences = true,
|
||||
bool SkipInvalidConverts = false,
|
||||
int? MaxParallelism = null,
|
||||
|
||||
@@ -19,7 +19,9 @@ public sealed class ObjectLoader(
|
||||
IProgress<ProgressArgs>? progress,
|
||||
ILogger<ObjectLoader> logger,
|
||||
CancellationToken cancellationToken
|
||||
#pragma warning disable CS9107 // Parameter is captured into the state of the enclosing type and its value is also passed to the base constructor. The value might be captured by the base class as well.
|
||||
) : ChannelLoader<BaseItem>(cancellationToken), IObjectLoader
|
||||
#pragma warning restore CS9107 // Parameter is captured into the state of the enclosing type and its value is also passed to the base constructor. The value might be captured by the base class as well.
|
||||
{
|
||||
private int? _allChildrenCount;
|
||||
private long _checkCache;
|
||||
@@ -27,7 +29,6 @@ public sealed class ObjectLoader(
|
||||
private long _downloaded;
|
||||
private long _totalToDownload;
|
||||
private DeserializeProcessOptions _options = new();
|
||||
private readonly CancellationToken _cancellationToken = cancellationToken;
|
||||
|
||||
[AutoInterfaceIgnore]
|
||||
public void Dispose() => sqLiteJsonCacheManager.Dispose();
|
||||
@@ -45,7 +46,7 @@ public sealed class ObjectLoader(
|
||||
{
|
||||
//assume everything exists as the root is there.
|
||||
var allChildren = ClosureParser
|
||||
.GetClosuresSorted(rootJson, _cancellationToken)
|
||||
.GetClosuresSorted(rootJson, cancellationToken)
|
||||
.Select(x => new Id(x.Item1))
|
||||
.ToList();
|
||||
//this probably yields away from the Main thread to let host apps update progress
|
||||
@@ -58,11 +59,11 @@ public sealed class ObjectLoader(
|
||||
if (!options.SkipServer)
|
||||
{
|
||||
rootJson = await serverObjectManager
|
||||
.DownloadSingleObject(rootId, progress, _cancellationToken)
|
||||
.DownloadSingleObject(rootId, progress, cancellationToken)
|
||||
.NotNull()
|
||||
.ConfigureAwait(false);
|
||||
IReadOnlyCollection<Id> allChildrenIds = ClosureParser
|
||||
.GetClosures(rootJson, _cancellationToken)
|
||||
.GetClosures(rootJson, cancellationToken)
|
||||
.OrderByDescending(x => x.Item2)
|
||||
.Select(x => new Id(x.Item1))
|
||||
.Where(x => !x.Value.StartsWith("blob", StringComparison.Ordinal))
|
||||
@@ -110,13 +111,12 @@ public sealed class ObjectLoader(
|
||||
await foreach (
|
||||
var (id, json) in serverObjectManager.DownloadObjects(
|
||||
ids.Select(x => x.NotNull()).ToList(),
|
||||
null, //TODO: Implement attribute masking in a safe way that will not poison SQLite DB.
|
||||
progress,
|
||||
_cancellationToken
|
||||
cancellationToken
|
||||
)
|
||||
)
|
||||
{
|
||||
_cancellationToken.ThrowIfCancellationRequested();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
Interlocked.Increment(ref _downloaded);
|
||||
progress?.Report(new(ProgressEvent.DownloadObjects, _downloaded, _totalToDownload));
|
||||
toCache.Add(new(new(id), new(json), true, null));
|
||||
@@ -138,7 +138,7 @@ public sealed class ObjectLoader(
|
||||
{
|
||||
if (!_options.SkipCache)
|
||||
{
|
||||
_cancellationToken.ThrowIfCancellationRequested();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
sqLiteJsonCacheManager.SaveObjects(batch.Select(x => (x.Id.Value, x.Json.Value)));
|
||||
Interlocked.Exchange(ref _cached, _cached + batch.Count);
|
||||
progress?.Report(new(ProgressEvent.CachedToLocal, _cached, _allChildrenCount));
|
||||
@@ -168,7 +168,7 @@ public sealed class ObjectLoader(
|
||||
private void ThrowIfFailed()
|
||||
{
|
||||
//always check for cancellation first
|
||||
_cancellationToken.ThrowIfCancellationRequested();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
if (Exception is not null)
|
||||
{
|
||||
throw new SpeckleException($"Error while loading: {Exception.Message}", Exception);
|
||||
|
||||
@@ -51,7 +51,6 @@ public class ServerObjectManager : IServerObjectManager
|
||||
|
||||
public async IAsyncEnumerable<(string, string)> DownloadObjects(
|
||||
IReadOnlyCollection<string> objectIds,
|
||||
string? attributeMask,
|
||||
IProgress<ProgressArgs>? progress,
|
||||
[EnumeratorCancellation] CancellationToken cancellationToken
|
||||
)
|
||||
@@ -60,14 +59,10 @@ public class ServerObjectManager : IServerObjectManager
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
using var childrenHttpMessage = new HttpRequestMessage();
|
||||
childrenHttpMessage.RequestUri = new Uri($"/api/v2/projects/{_streamId}/object-stream/", UriKind.Relative);
|
||||
childrenHttpMessage.RequestUri = new Uri($"/api/getobjects/{_streamId}", UriKind.Relative);
|
||||
childrenHttpMessage.Method = HttpMethod.Post;
|
||||
|
||||
Dictionary<string, object> postParameters = new() { { "objectIds", objectIds } };
|
||||
if (!string.IsNullOrWhiteSpace(attributeMask))
|
||||
{
|
||||
postParameters.Add("attributeMask", attributeMask.NotNull());
|
||||
}
|
||||
Dictionary<string, string> postParameters = new() { { "objects", JsonConvert.SerializeObject(objectIds) } };
|
||||
string serializedPayload = JsonConvert.SerializeObject(postParameters);
|
||||
childrenHttpMessage.Content = new StringContent(serializedPayload, Encoding.UTF8, "application/json");
|
||||
childrenHttpMessage.Headers.Add("Accept", "text/plain");
|
||||
|
||||
@@ -338,7 +338,6 @@ public class DummyServerObjectManager : IServerObjectManager
|
||||
{
|
||||
public IAsyncEnumerable<(string, string)> DownloadObjects(
|
||||
IReadOnlyCollection<string> objectIds,
|
||||
string? attributeMask,
|
||||
IProgress<ProgressArgs>? progress,
|
||||
CancellationToken cancellationToken
|
||||
) => throw new NotImplementedException();
|
||||
|
||||
@@ -113,14 +113,14 @@ public class ExceptionTests
|
||||
new ExceptionServerObjectManager(),
|
||||
null,
|
||||
new NullLogger<ObjectLoader>(),
|
||||
CancellationToken.None
|
||||
default
|
||||
);
|
||||
await using var process = new DeserializeProcess(
|
||||
o,
|
||||
null,
|
||||
new BaseDeserializer(new ObjectDeserializerFactory()),
|
||||
new NullLoggerFactory(),
|
||||
CancellationToken.None,
|
||||
default,
|
||||
new(SkipCache: true, MaxParallelism: 1, SkipServer: true)
|
||||
);
|
||||
|
||||
@@ -144,7 +144,7 @@ public class ExceptionTests
|
||||
null,
|
||||
new BaseDeserializer(new ObjectDeserializerFactory()),
|
||||
new NullLoggerFactory(),
|
||||
CancellationToken.None,
|
||||
default,
|
||||
new(true, MaxParallelism: 1)
|
||||
);
|
||||
|
||||
@@ -169,7 +169,7 @@ public class ExceptionTests
|
||||
null,
|
||||
new BaseDeserializer(new ObjectDeserializerFactory()),
|
||||
new NullLoggerFactory(),
|
||||
CancellationToken.None,
|
||||
default,
|
||||
new(MaxParallelism: 1)
|
||||
);
|
||||
|
||||
@@ -194,7 +194,9 @@ public class ExceptionTests
|
||||
[SpeckleType("Objects.Geometry.BadBase")]
|
||||
public class BadBase : Base
|
||||
{
|
||||
#pragma warning disable CA1065
|
||||
public string BadProp => throw new NotImplementedException();
|
||||
#pragma warning restore CA1065
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -8,7 +8,6 @@ public class ExceptionServerObjectManager : IServerObjectManager
|
||||
{
|
||||
public IAsyncEnumerable<(string, string)> DownloadObjects(
|
||||
IReadOnlyCollection<string> objectIds,
|
||||
string? attributeMask,
|
||||
IProgress<ProgressArgs>? progress,
|
||||
CancellationToken cancellationToken
|
||||
) => throw new NotImplementedException();
|
||||
|
||||
@@ -150,7 +150,7 @@ public class SerializationTests
|
||||
id.Should().Be(newId.Value);
|
||||
}
|
||||
|
||||
[Theory(Skip = "Takes too long")]
|
||||
[Theory]
|
||||
[InlineData("RevitObject.json.gz", "3416d3fe01c9196115514c4a2f41617b", 7818)]
|
||||
public async Task Roundtrip_Test_Old(string fileName, string _, int count)
|
||||
{
|
||||
@@ -186,6 +186,8 @@ public class SerializationTests
|
||||
|
||||
[Theory]
|
||||
[InlineData(1)]
|
||||
[InlineData(2)]
|
||||
[InlineData(3)]
|
||||
[InlineData(4)]
|
||||
public async Task Roundtrip_Test_New(int concurrency)
|
||||
{
|
||||
@@ -203,7 +205,7 @@ public class SerializationTests
|
||||
new DummyReceiveServerObjectManager(closures),
|
||||
null,
|
||||
new NullLogger<ObjectLoader>(),
|
||||
CancellationToken.None
|
||||
default
|
||||
)
|
||||
)
|
||||
{
|
||||
|
||||
@@ -31,17 +31,14 @@ public class ServerObjectManagerTests : MoqTest
|
||||
var jObject = new JObject { { "id", id }, { "value", true } };
|
||||
var jObject2 = new JObject { { "id", id2 }, { "value", true } };
|
||||
var mockHttp = new MockHttpMessageHandler();
|
||||
Dictionary<string, object> postParameters = new()
|
||||
Dictionary<string, string> postParameters = new()
|
||||
{
|
||||
{
|
||||
"objectIds",
|
||||
new List<string> { id, id2 }
|
||||
},
|
||||
{ "objects", JsonConvert.SerializeObject(new List<string> { id, id2 }) },
|
||||
};
|
||||
|
||||
string serializedPayload = JsonConvert.SerializeObject(postParameters);
|
||||
mockHttp
|
||||
.When(HttpMethod.Post, $"http://localhost/api/v2/projects/{streamId}/object-stream/")
|
||||
.When(HttpMethod.Post, $"http://localhost/api/getobjects/{streamId}")
|
||||
.WithContent(serializedPayload)
|
||||
.Respond(
|
||||
"application/json",
|
||||
@@ -62,7 +59,7 @@ public class ServerObjectManagerTests : MoqTest
|
||||
token,
|
||||
new(timeout: TimeSpan.FromSeconds(timeout))
|
||||
);
|
||||
var results = serverObjectManager.DownloadObjects(new List<string> { id, id2 }, null, null, ct);
|
||||
var results = serverObjectManager.DownloadObjects(new List<string> { id, id2 }, null, ct);
|
||||
var objects = new JObject();
|
||||
await foreach (var (x, json) in results)
|
||||
{
|
||||
|
||||
@@ -10,7 +10,6 @@ public class DummyReceiveServerObjectManager(IReadOnlyDictionary<string, string>
|
||||
{
|
||||
public async IAsyncEnumerable<(string, string)> DownloadObjects(
|
||||
IReadOnlyCollection<string> objectIds,
|
||||
string? attributeMask,
|
||||
IProgress<ProgressArgs>? progress,
|
||||
[EnumeratorCancellation] CancellationToken cancellationToken
|
||||
)
|
||||
|
||||
@@ -9,7 +9,6 @@ public class DummySendServerObjectManager(ConcurrentDictionary<string, string> s
|
||||
{
|
||||
public IAsyncEnumerable<(string, string)> DownloadObjects(
|
||||
IReadOnlyCollection<string> objectIds,
|
||||
string? attributeMask,
|
||||
IProgress<ProgressArgs>? progress,
|
||||
CancellationToken cancellationToken
|
||||
) => throw new NotImplementedException();
|
||||
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"Data": {},
|
||||
"Message": "Response status code does not indicate success: 404 (Not Found).",
|
||||
"StatusCode": "NotFound",
|
||||
"Type": "HttpRequestException"
|
||||
}
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"Data": {},
|
||||
"Message": "Response status code does not indicate success: 404 (Not Found).",
|
||||
"StatusCode": "NotFound",
|
||||
"Type": "HttpRequestException"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"ConvertedReferences": {},
|
||||
"RootId": "5313a8f61e1fa7abe9bf716ddfc767bd"
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"Data": {},
|
||||
"InnerException": {
|
||||
"$type": "SpeckleSerializeException",
|
||||
"Data": {},
|
||||
"InnerException": {
|
||||
"$type": "ArgumentException",
|
||||
"Data": {},
|
||||
"Message": "Unsupported value in serialization: System.Text.StringBuilder",
|
||||
"ParamName": "obj",
|
||||
"Type": "ArgumentException"
|
||||
},
|
||||
"Message": "Failed to extract (pre-serialize) properties from the Speckle.Sdk.Models.Base",
|
||||
"Type": "SpeckleSerializeException"
|
||||
},
|
||||
"Message": "Error while sending: Failed to extract (pre-serialize) properties from the Speckle.Sdk.Models.Base",
|
||||
"Type": "SpeckleException"
|
||||
}
|
||||
@@ -1,190 +0,0 @@
|
||||
using System.Reflection;
|
||||
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;
|
||||
|
||||
public sealed class SendReceiveTests : IAsyncLifetime
|
||||
{
|
||||
private Project _project;
|
||||
private IClient _client;
|
||||
private IOperations _operations;
|
||||
private const string NON_EXISTENT_OBJECT_ID = "0a480dfb7aa774f19a82bee9d6320abd";
|
||||
private const string NON_EXISTENT_PROJECT_ID = "8cdc651d13";
|
||||
|
||||
public async Task InitializeAsync()
|
||||
{
|
||||
TypeLoader.Reset();
|
||||
TypeLoader.Initialize(typeof(Base).Assembly, Assembly.GetExecutingAssembly());
|
||||
var serviceProvider = TestServiceSetup.GetServiceProvider();
|
||||
_operations = serviceProvider.GetRequiredService<IOperations>();
|
||||
ClearCache();
|
||||
|
||||
_client = await Fixtures.SeedUserWithClient();
|
||||
_project = await _client.Project.Create(new("Blobber", "Flobber", ProjectVisibility.Private));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendAndReceive()
|
||||
{
|
||||
var myObject = Fixtures.GenerateNestedObject();
|
||||
string expectedId = myObject.GetId(true);
|
||||
|
||||
//SEND
|
||||
var fistSend = await _operations.Send2(
|
||||
_client.ServerUrl,
|
||||
_project.id,
|
||||
_client.Account.token,
|
||||
myObject,
|
||||
null,
|
||||
CancellationToken.None
|
||||
);
|
||||
|
||||
Assert.Equal(expectedId, fistSend.RootId);
|
||||
await Verify(fistSend);
|
||||
|
||||
//RECEIVE
|
||||
var received = await _operations.Receive2(
|
||||
_client.ServerUrl,
|
||||
_project.id,
|
||||
fistSend.RootId,
|
||||
_client.Account.token,
|
||||
null,
|
||||
CancellationToken.None
|
||||
);
|
||||
|
||||
Assert.Equal(expectedId, received.id);
|
||||
|
||||
//SEND AGAIN!
|
||||
var secondSend = await _operations.Send2(
|
||||
_client.ServerUrl,
|
||||
_project.id,
|
||||
_client.Account.token,
|
||||
received,
|
||||
null,
|
||||
CancellationToken.None
|
||||
);
|
||||
|
||||
Assert.Equal(expectedId, secondSend.RootId);
|
||||
|
||||
//RECEIVE AGAIN, but using cache
|
||||
ClearCache();
|
||||
var secondReceive = await _operations.Receive2(
|
||||
_client.ServerUrl,
|
||||
_project.id,
|
||||
fistSend.RootId,
|
||||
_client.Account.token,
|
||||
null,
|
||||
CancellationToken.None
|
||||
);
|
||||
|
||||
Assert.Equal(expectedId, secondReceive.id);
|
||||
}
|
||||
|
||||
private void ClearCache() { }
|
||||
|
||||
[Fact]
|
||||
public async Task ReceiveNonExistentObjectThrows()
|
||||
{
|
||||
var ex = await Assert.ThrowsAsync<HttpRequestException>(async () =>
|
||||
{
|
||||
_ = await _operations.Receive2(
|
||||
_client.ServerUrl,
|
||||
_project.id,
|
||||
NON_EXISTENT_OBJECT_ID,
|
||||
_client.Account.token,
|
||||
null,
|
||||
CancellationToken.None,
|
||||
new(true)
|
||||
);
|
||||
});
|
||||
await Verify(ex);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ReceiveNonExistentProjectThrows()
|
||||
{
|
||||
var ex = await Assert.ThrowsAsync<HttpRequestException>(async () =>
|
||||
{
|
||||
_ = await _operations.Receive2(
|
||||
_client.ServerUrl,
|
||||
NON_EXISTENT_PROJECT_ID,
|
||||
NON_EXISTENT_OBJECT_ID,
|
||||
_client.Account.token,
|
||||
null,
|
||||
CancellationToken.None,
|
||||
new(true)
|
||||
);
|
||||
});
|
||||
await Verify(ex);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendInvalidData()
|
||||
{
|
||||
var myObject = Fixtures.GenerateNestedObject();
|
||||
myObject["invalidProp"] = new StringBuilder(); //Serializer does not support serializing this type
|
||||
|
||||
var ex = await Assert.ThrowsAsync<SpeckleException>(async () =>
|
||||
{
|
||||
_ = await _operations.Send2(
|
||||
_client.ServerUrl,
|
||||
_project.id,
|
||||
_client.Account.token,
|
||||
myObject,
|
||||
null,
|
||||
CancellationToken.None,
|
||||
new(SkipCacheRead: true, SkipCacheWrite: true)
|
||||
);
|
||||
});
|
||||
await Verify(ex);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ReceiveNonAuthThrows()
|
||||
{
|
||||
using IClient unauthed = Fixtures.Unauthed;
|
||||
await Assert.ThrowsAsync<HttpRequestException>(async () =>
|
||||
{
|
||||
_ = await _operations.Receive2(
|
||||
unauthed.ServerUrl,
|
||||
_project.id,
|
||||
NON_EXISTENT_OBJECT_ID,
|
||||
unauthed.Account.token,
|
||||
null,
|
||||
CancellationToken.None,
|
||||
new(true)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ReceiveCancellation()
|
||||
{
|
||||
using CancellationTokenSource ct = new();
|
||||
await ct.CancelAsync();
|
||||
await Assert.ThrowsAnyAsync<OperationCanceledException>(async () =>
|
||||
{
|
||||
_ = await _operations.Receive2(
|
||||
_client.ServerUrl,
|
||||
_project.id,
|
||||
NON_EXISTENT_OBJECT_ID,
|
||||
_client.Account.token,
|
||||
null,
|
||||
ct.Token,
|
||||
new(true)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
public Task DisposeAsync()
|
||||
{
|
||||
_client?.Dispose();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user