Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3fbd9c17ba | |||
| 937eb94730 | |||
| b0da4510bf | |||
| 96392d0d2f |
@@ -33,6 +33,9 @@ jobs:
|
||||
|
||||
- name: 🔨 Unit Tests
|
||||
run: dotnet test ${{ env.Solution }} --configuration Release --filter "Category!=Integration" --no-build --no-restore --verbosity=normal /p:AltCover=true /p:AltCoverAttributeFilter=ExcludeFromCodeCoverage
|
||||
|
||||
- name: 🎁 Pack
|
||||
run: dotnet pack ${{ env.Solution }} --configuration Release --no-build
|
||||
|
||||
- name: Upload coverage reports to Codecov with GitHub Action
|
||||
uses: codecov/codecov-action@v5
|
||||
|
||||
@@ -42,6 +42,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.github\workflows\pr.yml = .github\workflows\pr.yml
|
||||
.github\workflows\release.yml = .github\workflows\release.yml
|
||||
.github\workflows\integration-test.yml = .github\workflows\integration-test.yml
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Speckle.Sdk.Tests.Performance", "tests\Speckle.Sdk.Tests.Performance\Speckle.Sdk.Tests.Performance.csproj", "{870E3396-E6F7-43AE-B120-E651FA4F46BD}"
|
||||
|
||||
@@ -35,6 +35,7 @@ public sealed class Client : ISpeckleGraphQLClient, IClient
|
||||
public WorkspaceResource Workspace { get; }
|
||||
public ServerResource Server { get; }
|
||||
public FileImportResource FileImport { get; }
|
||||
public IngestResource Ingest { get; }
|
||||
|
||||
public Uri ServerUrl => new(Account.serverInfo.url);
|
||||
|
||||
@@ -71,6 +72,7 @@ public sealed class Client : ISpeckleGraphQLClient, IClient
|
||||
Workspace = new(this);
|
||||
Server = new(this);
|
||||
FileImport = new(this, blobApiFactory.Create(account));
|
||||
Ingest = new(this);
|
||||
}
|
||||
|
||||
[AutoInterfaceIgnore]
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
namespace Speckle.Sdk.Api.GraphQL.Inputs;
|
||||
|
||||
public record IngestCreateInput(
|
||||
string fileName,
|
||||
int? maxIdleTimeoutMinutes,
|
||||
string modelId,
|
||||
string projectId,
|
||||
string sourceApplication,
|
||||
string sourceApplicationVersion,
|
||||
IReadOnlyDictionary<string, object?> sourceFileData
|
||||
);
|
||||
|
||||
public record IngestFinishInput(string id, string? message, string objectId, string projectId);
|
||||
|
||||
public record IngestErrorInput(string errorReason, string errorStacktrace, string id, string projectId);
|
||||
|
||||
public record CancelRequestInput(string id, string projectId);
|
||||
|
||||
public record IngestUpdateInput(string id, double? progress, string? progressMessage, string projectId);
|
||||
@@ -0,0 +1,23 @@
|
||||
namespace Speckle.Sdk.Api.GraphQL.Models;
|
||||
|
||||
public sealed class Ingest
|
||||
{
|
||||
public required DateTime createdAt { get; init; }
|
||||
public required string errorReason { get; init; }
|
||||
public required string errorStacktrace { get; init; }
|
||||
public required string fileName { get; init; }
|
||||
public required string id { get; init; }
|
||||
public required long maxIdleTimeoutMinutes { get; init; }
|
||||
public required string modelId { get; init; }
|
||||
public required Dictionary<string, object?> performanceData { get; init; }
|
||||
public required double progress { get; init; }
|
||||
public required string? progressMessage { get; init; }
|
||||
public required string projectId { get; init; }
|
||||
public required string sourceApplication { get; init; }
|
||||
public required string sourceApplicationVersion { get; init; }
|
||||
public required Dictionary<string, object?> sourceFileData { get; init; }
|
||||
public required string status { get; init; }
|
||||
public required DateTime updatedAt { get; init; }
|
||||
public required string versionId { get; init; }
|
||||
public required LimitedUser user { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
using GraphQL;
|
||||
using Speckle.Sdk.Api.GraphQL.Inputs;
|
||||
using Speckle.Sdk.Api.GraphQL.Models;
|
||||
using Speckle.Sdk.Api.GraphQL.Models.Responses;
|
||||
using Version = Speckle.Sdk.Api.GraphQL.Models.Version;
|
||||
|
||||
namespace Speckle.Sdk.Api.GraphQL.Resources;
|
||||
|
||||
public sealed class IngestResource
|
||||
{
|
||||
private readonly ISpeckleGraphQLClient _client;
|
||||
|
||||
internal IngestResource(ISpeckleGraphQLClient client)
|
||||
{
|
||||
_client = client;
|
||||
}
|
||||
|
||||
/// <param name="modelId"></param>
|
||||
/// <param name="projectId"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
/// <inheritdoc cref="ISpeckleGraphQLClient.ExecuteGraphQLRequest{T}"/>
|
||||
public async Task<ResourceCollection<Ingest>> GetIngests(
|
||||
string modelId,
|
||||
string projectId,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
//language=graphql
|
||||
const string QUERY = """
|
||||
query GetIngest($modelId: String!, $projectId: String!) {
|
||||
data:project(id: $projectId) {
|
||||
data:model(id: $modelId) {
|
||||
data:ingests {
|
||||
cursor
|
||||
items {
|
||||
createdAt
|
||||
errorReason
|
||||
errorStacktrace
|
||||
fileName
|
||||
id
|
||||
maxIdleTimeoutMinutes
|
||||
modelId
|
||||
performanceData
|
||||
progress
|
||||
progressMessage
|
||||
projectId
|
||||
sourceApplication
|
||||
sourceApplicationVersion
|
||||
sourceFileData
|
||||
status
|
||||
updatedAt
|
||||
versionId
|
||||
user {
|
||||
avatar
|
||||
bio
|
||||
company
|
||||
id
|
||||
name
|
||||
role
|
||||
verified
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
var request = new GraphQLRequest { Query = QUERY, Variables = new { modelId, projectId } };
|
||||
|
||||
var response = await _client
|
||||
.ExecuteGraphQLRequest<RequiredResponse<RequiredResponse<RequiredResponse<ResourceCollection<Ingest>>>>>(
|
||||
request,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return response.data.data.data;
|
||||
}
|
||||
|
||||
/// <param name="input"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
/// <inheritdoc cref="ISpeckleGraphQLClient.ExecuteGraphQLRequest{T}"/>
|
||||
public async Task<bool> Update(IngestUpdateInput input, CancellationToken cancellationToken = default)
|
||||
{
|
||||
//language=graphql
|
||||
const string QUERY = """
|
||||
mutation IngestUpdate($projectId: ID!, $input: IngestUpdateInput!) {
|
||||
data: projectMutations {
|
||||
data: ingestMutations(projectId: $projectId) {
|
||||
data: update(input: $input)
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
GraphQLRequest request = new() { Query = QUERY, Variables = new { input, input.projectId } };
|
||||
|
||||
var res = await _client
|
||||
.ExecuteGraphQLRequest<RequiredResponse<RequiredResponse<RequiredResponse<bool>>>>(request, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return res.data.data.data;
|
||||
}
|
||||
|
||||
/// <param name="input"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
/// <inheritdoc cref="ISpeckleGraphQLClient.ExecuteGraphQLRequest{T}"/>
|
||||
public async Task<Ingest> Create(IngestCreateInput input, CancellationToken cancellationToken = default)
|
||||
{
|
||||
//language=graphql
|
||||
const string QUERY = """
|
||||
mutation IngestCreate($projectId: ID!, $input: IngestCreateInput!) {
|
||||
data: projectMutations {
|
||||
data:ingestMutations(projectId: $projectId) {
|
||||
data:create(input: $input) {
|
||||
createdAt
|
||||
errorReason
|
||||
errorStacktrace
|
||||
fileName
|
||||
id
|
||||
maxIdleTimeoutMinutes
|
||||
modelId
|
||||
performanceData
|
||||
progress
|
||||
progressMessage
|
||||
projectId
|
||||
sourceApplication
|
||||
sourceApplicationVersion
|
||||
sourceFileData
|
||||
status
|
||||
updatedAt
|
||||
versionId
|
||||
user {
|
||||
avatar
|
||||
bio
|
||||
company
|
||||
id
|
||||
name
|
||||
role
|
||||
verified
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
GraphQLRequest request = new() { Query = QUERY, Variables = new { input, input.projectId } };
|
||||
|
||||
var res = await _client
|
||||
.ExecuteGraphQLRequest<RequiredResponse<RequiredResponse<RequiredResponse<Ingest>>>>(request, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return res.data.data.data;
|
||||
}
|
||||
|
||||
/// <param name="input"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
/// <inheritdoc cref="ISpeckleGraphQLClient.ExecuteGraphQLRequest{T}"/>
|
||||
public async Task<Version> End(IngestFinishInput input, CancellationToken cancellationToken = default)
|
||||
{
|
||||
//language=graphql
|
||||
const string QUERY = """
|
||||
mutation IngestEnd($projectId: ID!, $input: IngestFinishInput!) {
|
||||
data: projectMutations {
|
||||
data:ingestMutations(projectId: $projectId) {
|
||||
data:end(input: $input) {
|
||||
id
|
||||
referencedObject
|
||||
message
|
||||
sourceApplication
|
||||
createdAt
|
||||
previewUrl
|
||||
authorUser {
|
||||
id
|
||||
name
|
||||
bio
|
||||
company
|
||||
verified
|
||||
role
|
||||
avatar
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
GraphQLRequest request = new() { Query = QUERY, Variables = new { input, input.projectId } };
|
||||
|
||||
var res = await _client
|
||||
.ExecuteGraphQLRequest<RequiredResponse<RequiredResponse<RequiredResponse<Version>>>>(request, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return res.data.data.data;
|
||||
}
|
||||
|
||||
/// <param name="input"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
/// <inheritdoc cref="ISpeckleGraphQLClient.ExecuteGraphQLRequest{T}"/>
|
||||
public async Task<bool> Error(IngestErrorInput input, CancellationToken cancellationToken = default)
|
||||
{
|
||||
//language=graphql
|
||||
const string QUERY = """
|
||||
mutation IngestError($projectId: ID!, $input: IngestErrorInput!) {
|
||||
data: projectMutations {
|
||||
data:ingestMutations(projectId: $projectId) {
|
||||
data:error(input: $input)
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
GraphQLRequest request = new() { Query = QUERY, Variables = new { input, input.projectId } };
|
||||
|
||||
var res = await _client
|
||||
.ExecuteGraphQLRequest<RequiredResponse<RequiredResponse<RequiredResponse<bool>>>>(request, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return res.data.data.data;
|
||||
}
|
||||
|
||||
/// <param name="input"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
/// <inheritdoc cref="ISpeckleGraphQLClient.ExecuteGraphQLRequest{T}"/>
|
||||
public async Task<bool> Cancel(CancelRequestInput input, CancellationToken cancellationToken = default)
|
||||
{
|
||||
//language=graphql
|
||||
const string QUERY = """
|
||||
mutation IngestCancel($projectId: ID!, $input: CancelRequestInput!) {
|
||||
data:projectMutations {
|
||||
data:ingestMutations(projectId: $projectId) {
|
||||
data:cancel(input: $input)
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
GraphQLRequest request = new() { Query = QUERY, Variables = new { input, input.projectId } };
|
||||
|
||||
var res = await _client
|
||||
.ExecuteGraphQLRequest<RequiredResponse<RequiredResponse<RequiredResponse<bool>>>>(request, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return res.data.data.data;
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
using System.Reflection;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
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;
|
||||
using Speckle.Sdk.Transports;
|
||||
|
||||
namespace Speckle.Sdk.Tests.Integration.API.GraphQL.Resources;
|
||||
|
||||
public class IngestResourceTests : IAsyncLifetime
|
||||
{
|
||||
private IClient _testUser;
|
||||
private IngestResource Sut => _testUser.Ingest;
|
||||
private Project _project;
|
||||
private Model _model;
|
||||
private IOperations _operations;
|
||||
|
||||
public Task DisposeAsync() => Task.CompletedTask;
|
||||
|
||||
public async Task InitializeAsync()
|
||||
{
|
||||
TypeLoader.Reset();
|
||||
TypeLoader.Initialize(typeof(Base).Assembly, Assembly.GetExecutingAssembly());
|
||||
var serviceProvider = TestServiceSetup.GetServiceProvider();
|
||||
_operations = serviceProvider.GetRequiredService<IOperations>();
|
||||
|
||||
_testUser = await Fixtures.SeedUserWithClient();
|
||||
_project = await _testUser.Project.Create(new("Test project", "", null));
|
||||
_model = await _testUser.Model.Create(new("Test Model 1", "", _project.id));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateAndError()
|
||||
{
|
||||
var input = new IngestCreateInput(
|
||||
"myTestFile",
|
||||
1,
|
||||
_model.id,
|
||||
_project.id,
|
||||
".NET",
|
||||
"0.0.0",
|
||||
new Dictionary<string, object?>()
|
||||
);
|
||||
Ingest ingest = await Sut.Create(input);
|
||||
|
||||
var errorInput = new IngestErrorInput("A bad thing happened", "Over hear!", ingest.id, _project.id);
|
||||
var res = await Sut.Error(errorInput);
|
||||
Assert.True(res);
|
||||
|
||||
var result = await Sut.GetIngests(_model.id, _project.id);
|
||||
|
||||
await Verify(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateAndCancel()
|
||||
{
|
||||
var input = new IngestCreateInput(
|
||||
"myTestFile",
|
||||
1,
|
||||
_model.id,
|
||||
_project.id,
|
||||
".NET",
|
||||
"0.0.0",
|
||||
new Dictionary<string, object?>()
|
||||
);
|
||||
Ingest ingest = await Sut.Create(input);
|
||||
|
||||
var errorInput = new CancelRequestInput(ingest.id, _project.id);
|
||||
var res = await Sut.Cancel(errorInput);
|
||||
Assert.True(res);
|
||||
|
||||
var result = await Sut.GetIngests(_model.id, _project.id);
|
||||
|
||||
await Verify(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateAndEnd()
|
||||
{
|
||||
var create = new IngestCreateInput(
|
||||
"myTestFile",
|
||||
1,
|
||||
_model.id,
|
||||
_project.id,
|
||||
".NET",
|
||||
"0.0.0",
|
||||
new Dictionary<string, object?>()
|
||||
);
|
||||
Ingest ingest = await Sut.Create(create);
|
||||
|
||||
var myObject = Fixtures.GenerateNestedObject();
|
||||
var sendResult = await _operations.Send2(
|
||||
_testUser.ServerUrl,
|
||||
_project.id,
|
||||
_testUser.Account.token,
|
||||
myObject,
|
||||
new Progress<ProgressArgs>(x =>
|
||||
{
|
||||
var updateInput = new IngestUpdateInput(
|
||||
ingest.id,
|
||||
x.Total == null ? null : x.Count / x.Total,
|
||||
$"{x.Count} / {x.Total}",
|
||||
_project.id
|
||||
);
|
||||
_ = Sut.Update(updateInput).Result;
|
||||
}),
|
||||
CancellationToken.None,
|
||||
new(true, true)
|
||||
);
|
||||
|
||||
var finish = new IngestFinishInput(ingest.id, "Yay! we completed", sendResult.RootId, _project.id);
|
||||
var res = await Sut.End(finish);
|
||||
Assert.NotNull(res);
|
||||
|
||||
var result = await Sut.GetIngests(_model.id, _project.id);
|
||||
await Verify(result);
|
||||
}
|
||||
}
|
||||
+31
-30
@@ -10,7 +10,12 @@ namespace Speckle.Sdk.Tests.Integration.API.GraphQL.Resources;
|
||||
|
||||
public class SubscriptionResourceTests : IAsyncLifetime
|
||||
{
|
||||
private const int WAIT_PERIOD = 300;
|
||||
#if DEBUG
|
||||
private const int WAIT_PERIOD = 3000; // 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
|
||||
#endif
|
||||
private const int TIMEOUT = WAIT_PERIOD + WAIT_PERIOD + 400;
|
||||
private IClient _testUser;
|
||||
private Project _testProject;
|
||||
private Model _testModel;
|
||||
@@ -32,105 +37,101 @@ public class SubscriptionResourceTests : IAsyncLifetime
|
||||
_testVersion = await Fixtures.CreateVersion(_testUser, _testProject.id, _testModel.id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Fact(Timeout = TIMEOUT)]
|
||||
public async Task UserProjectsUpdated_SubscriptionIsCalled()
|
||||
{
|
||||
UserProjectsUpdatedMessage? subscriptionMessage = null;
|
||||
|
||||
TaskCompletionSource<UserProjectsUpdatedMessage> tcs = new();
|
||||
using var sub = Sut.CreateUserProjectsUpdatedSubscription();
|
||||
sub.Listeners += (_, message) => subscriptionMessage = message;
|
||||
sub.Listeners += (_, message) => tcs.SetResult(message);
|
||||
|
||||
await Task.Delay(WAIT_PERIOD); // Give time to subscription to be setup
|
||||
|
||||
var created = await _testUser.Project.Create(new(null, null, null));
|
||||
|
||||
await Task.Delay(WAIT_PERIOD); // Give time for subscription to be triggered
|
||||
var subscriptionMessage = await tcs.Task;
|
||||
|
||||
subscriptionMessage.Should().NotBeNull();
|
||||
subscriptionMessage!.id.Should().Be(created.id);
|
||||
subscriptionMessage.id.Should().Be(created.id);
|
||||
subscriptionMessage.type.Should().Be(UserProjectsUpdatedMessageType.ADDED);
|
||||
subscriptionMessage.project.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Fact(Timeout = TIMEOUT)]
|
||||
public async Task ProjectModelsUpdated_SubscriptionIsCalled()
|
||||
{
|
||||
ProjectModelsUpdatedMessage? subscriptionMessage = null;
|
||||
|
||||
TaskCompletionSource<ProjectModelsUpdatedMessage> tcs = new();
|
||||
using var sub = Sut.CreateProjectModelsUpdatedSubscription(_testProject.id);
|
||||
sub.Listeners += (_, message) => subscriptionMessage = message;
|
||||
sub.Listeners += (_, message) => tcs.SetResult(message);
|
||||
|
||||
await Task.Delay(WAIT_PERIOD); // Give time to subscription to be setup
|
||||
|
||||
CreateModelInput input = new("my model", "myDescription", _testProject.id);
|
||||
var created = await _testUser.Model.Create(input);
|
||||
|
||||
await Task.Delay(WAIT_PERIOD); // Give time for subscription to be triggered
|
||||
var subscriptionMessage = await tcs.Task;
|
||||
|
||||
subscriptionMessage.Should().NotBeNull();
|
||||
subscriptionMessage!.id.Should().Be(created.id);
|
||||
subscriptionMessage.id.Should().Be(created.id);
|
||||
subscriptionMessage.type.Should().Be(ProjectModelsUpdatedMessageType.CREATED);
|
||||
subscriptionMessage.model.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Fact(Timeout = TIMEOUT)]
|
||||
public async Task ProjectUpdated_SubscriptionIsCalled()
|
||||
{
|
||||
ProjectUpdatedMessage? subscriptionMessage = null;
|
||||
|
||||
TaskCompletionSource<ProjectUpdatedMessage> tcs = new();
|
||||
using var sub = Sut.CreateProjectUpdatedSubscription(_testProject.id);
|
||||
sub.Listeners += (_, message) => subscriptionMessage = message;
|
||||
sub.Listeners += (_, message) => tcs.SetResult(message);
|
||||
|
||||
await Task.Delay(WAIT_PERIOD); // Give time to subscription to be setup
|
||||
|
||||
var input = new ProjectUpdateInput(_testProject.id, "This is my new name");
|
||||
var created = await _testUser.Project.Update(input);
|
||||
|
||||
await Task.Delay(WAIT_PERIOD); // Give time for subscription to be triggered
|
||||
var subscriptionMessage = await tcs.Task;
|
||||
|
||||
subscriptionMessage.Should().NotBeNull();
|
||||
subscriptionMessage!.id.Should().Be(created.id);
|
||||
subscriptionMessage.id.Should().Be(created.id);
|
||||
subscriptionMessage.type.Should().Be(ProjectUpdatedMessageType.UPDATED);
|
||||
subscriptionMessage.project.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Fact(Timeout = TIMEOUT)]
|
||||
public async Task ProjectVersionsUpdated_SubscriptionIsCalled()
|
||||
{
|
||||
ProjectVersionsUpdatedMessage? subscriptionMessage = null;
|
||||
|
||||
TaskCompletionSource<ProjectVersionsUpdatedMessage> tcs = new();
|
||||
using var sub = Sut.CreateProjectVersionsUpdatedSubscription(_testProject.id);
|
||||
sub.Listeners += (_, message) => subscriptionMessage = message;
|
||||
sub.Listeners += (_, message) => tcs.SetResult(message);
|
||||
|
||||
await Task.Delay(WAIT_PERIOD); // Give time to subscription to be setup
|
||||
|
||||
var created = await Fixtures.CreateVersion(_testUser, _testProject.id, _testModel.id);
|
||||
|
||||
await Task.Delay(WAIT_PERIOD); // Give time for subscription to be triggered
|
||||
var subscriptionMessage = await tcs.Task;
|
||||
|
||||
subscriptionMessage.Should().NotBeNull();
|
||||
subscriptionMessage!.id.Should().Be(created.id);
|
||||
subscriptionMessage.id.Should().Be(created.id);
|
||||
subscriptionMessage.type.Should().Be(ProjectVersionsUpdatedMessageType.CREATED);
|
||||
subscriptionMessage.version.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact(Skip = CommentResourceTests.SERVER_SKIP_MESSAGE)]
|
||||
[Fact(Skip = CommentResourceTests.SERVER_SKIP_MESSAGE, Timeout = TIMEOUT)]
|
||||
public async Task ProjectCommentsUpdated_SubscriptionIsCalled()
|
||||
{
|
||||
string resourceIdString = $"{_testProject.id},{_testModel.id},{_testVersion}";
|
||||
ProjectCommentsUpdatedMessage? subscriptionMessage = null;
|
||||
|
||||
TaskCompletionSource<ProjectCommentsUpdatedMessage> tcs = new();
|
||||
using var sub = Sut.CreateProjectCommentsUpdatedSubscription(new(_testProject.id, resourceIdString));
|
||||
sub.Listeners += (_, message) => subscriptionMessage = message;
|
||||
sub.Listeners += (_, message) => tcs.SetResult(message);
|
||||
|
||||
await Task.Delay(WAIT_PERIOD); // Give time to subscription to be setup
|
||||
|
||||
var created = await Fixtures.CreateComment(_testUser, _testProject.id, _testModel.id, _testVersion.id);
|
||||
|
||||
await Task.Delay(WAIT_PERIOD); // Give time for subscription to be triggered
|
||||
var subscriptionMessage = await tcs.Task;
|
||||
|
||||
subscriptionMessage.Should().NotBeNull();
|
||||
subscriptionMessage!.id.Should().Be(created.id);
|
||||
subscriptionMessage.id.Should().Be(created.id);
|
||||
subscriptionMessage.type.Should().Be(ProjectCommentsUpdatedMessageType.CREATED);
|
||||
subscriptionMessage.comment.Should().NotBeNull();
|
||||
}
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
using FluentAssertions;
|
||||
using GraphQL.Client.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Speckle.Sdk.Api.GraphQL.Models;
|
||||
using Speckle.Sdk.Credentials;
|
||||
|
||||
namespace Speckle.Sdk.Tests.Integration.Credentials;
|
||||
|
||||
public class UserServerInfoTests : IAsyncLifetime
|
||||
{
|
||||
private Account _acc;
|
||||
|
||||
public Task DisposeAsync() => Task.CompletedTask;
|
||||
|
||||
public async Task InitializeAsync()
|
||||
{
|
||||
_acc = await Fixtures.SeedUser();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task IsFrontEnd2True()
|
||||
{
|
||||
ServerInfo result = await Fixtures
|
||||
.ServiceProvider.GetRequiredService<IAccountManager>()
|
||||
.GetServerInfo(new("https://app.speckle.systems/"));
|
||||
|
||||
result.Should().NotBeNull();
|
||||
result.frontend2.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetServerInfo_ExpectFail_NoServer()
|
||||
{
|
||||
Uri serverUrl = new("http://invalidserver.local");
|
||||
|
||||
await FluentActions
|
||||
.Invoking(async () =>
|
||||
await Fixtures.ServiceProvider.GetRequiredService<IAccountManager>().GetServerInfo(serverUrl)
|
||||
)
|
||||
.Should()
|
||||
.ThrowAsync<HttpRequestException>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetUserInfo()
|
||||
{
|
||||
Uri serverUrl = new(_acc.serverInfo.url);
|
||||
UserInfo result = await Fixtures
|
||||
.ServiceProvider.GetRequiredService<IAccountManager>()
|
||||
.GetUserInfo(_acc.token, serverUrl);
|
||||
|
||||
result.id.Should().Be(_acc.userInfo.id);
|
||||
result.name.Should().Be(_acc.userInfo.name);
|
||||
result.email.Should().Be(_acc.userInfo.email);
|
||||
result.company.Should().Be(_acc.userInfo.company);
|
||||
result.avatar.Should().Be(_acc.userInfo.avatar);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetUserInfo_ExpectFail_NoServer()
|
||||
{
|
||||
Uri serverUrl = new("http://invalidserver.local");
|
||||
|
||||
await FluentActions
|
||||
.Invoking(async () =>
|
||||
await Fixtures.ServiceProvider.GetRequiredService<IAccountManager>().GetUserInfo("", serverUrl)
|
||||
)
|
||||
.Should()
|
||||
.ThrowAsync<HttpRequestException>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetUserInfo_ExpectFail_NoUser()
|
||||
{
|
||||
Uri serverUrl = new(_acc.serverInfo.url);
|
||||
await FluentActions
|
||||
.Invoking(async () =>
|
||||
await Fixtures
|
||||
.ServiceProvider.GetRequiredService<IAccountManager>()
|
||||
.GetUserInfo("Bearer 08913c3c1e7ac65d779d1e1f11b942a44ad9672ca9", serverUrl)
|
||||
)
|
||||
.Should()
|
||||
.ThrowAsync<GraphQLHttpRequestException>();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user