Merge branch 'master' into dev

This commit is contained in:
tgstation-server-ci[bot]
2024-10-11 17:57:02 +00:00
8 changed files with 123 additions and 98 deletions
-1
View File
@@ -41,7 +41,6 @@ env:
TGS_WEBPANEL_NODE_VERSION: 20.x
TGS_TEST_GITHUB_TOKEN: ${{ secrets.LIVE_TESTS_TOKEN }}
PACKAGING_PRIVATE_KEY_PASSPHRASE: ${{ secrets.PACKAGING_PRIVATE_KEY_PASSPHRASE }}
Internal__EnableGraphQL: true
concurrency:
group: "ci-${{ (github.event_name != 'push' && github.event_name != 'schedule' && github.event.inputs.pull_request_number) || github.run_id }}-${{ github.event_name }}"
+1 -1
View File
@@ -3,7 +3,7 @@
<!-- Integration tests will ensure they match across the board -->
<Import Project="WebpanelVersion.props" />
<PropertyGroup>
<TgsCoreVersion>6.11.0</TgsCoreVersion>
<TgsCoreVersion>6.11.1</TgsCoreVersion>
<TgsConfigVersion>5.3.0</TgsConfigVersion>
<TgsRestVersion>10.10.0</TgsRestVersion>
<TgsGraphQLVersion>0.2.0</TgsGraphQLVersion>
+44 -45
View File
@@ -295,55 +295,54 @@ namespace Tgstation.Server.Host.Core
services.AddSingleton<IAbstractHttpClientFactory, AbstractHttpClientFactory>();
// configure graphql
if (postSetupServices.InternalConfiguration.EnableGraphQL)
services
.AddScoped<GraphQL.Subscriptions.ITopicEventReceiver, ShutdownAwareTopicEventReceiver>()
.AddGraphQLServer()
.AddAuthorization()
.ModifyOptions(options =>
{
options.EnsureAllNodesCanBeResolved = true;
options.EnableFlagEnums = true;
})
services
.AddScoped<GraphQL.Subscriptions.ITopicEventReceiver, ShutdownAwareTopicEventReceiver>()
.AddGraphQLServer()
.AddAuthorization()
.ModifyOptions(options =>
{
options.EnsureAllNodesCanBeResolved = true;
options.EnableFlagEnums = true;
})
#if DEBUG
.ModifyCostOptions(options =>
{
options.EnforceCostLimits = false;
})
.ModifyCostOptions(options =>
{
options.EnforceCostLimits = false;
})
#endif
.AddMutationConventions()
.AddInMemorySubscriptions(
new SubscriptionOptions
{
TopicBufferCapacity = 1024, // mainly so high for tests, not possible to DoS the server without authentication and some other access to generate messages
})
.AddGlobalObjectIdentification()
.AddQueryFieldToMutationPayloads()
.ModifyOptions(options =>
.AddMutationConventions()
.AddInMemorySubscriptions(
new SubscriptionOptions
{
options.EnableDefer = true;
TopicBufferCapacity = 1024, // mainly so high for tests, not possible to DoS the server without authentication and some other access to generate messages
})
.ModifyPagingOptions(pagingOptions =>
{
pagingOptions.IncludeTotalCount = true;
pagingOptions.RequirePagingBoundaries = false;
pagingOptions.DefaultPageSize = ApiController.DefaultPageSize;
pagingOptions.MaxPageSize = ApiController.MaximumPageSize;
})
.AddFiltering()
.AddSorting()
.AddHostTypes()
.AddErrorFilter<ErrorMessageFilter>()
.AddType<StandaloneNode>()
.AddType<LocalGateway>()
.AddType<RemoteGateway>()
.AddType<GraphQL.Types.UserName>()
.AddType<UnsignedIntType>()
.BindRuntimeType<Version, SemverType>()
.TryAddTypeInterceptor<RightsTypeInterceptor>()
.AddQueryType<Query>()
.AddMutationType<Mutation>()
.AddSubscriptionType<Subscription>();
.AddGlobalObjectIdentification()
.AddQueryFieldToMutationPayloads()
.ModifyOptions(options =>
{
options.EnableDefer = true;
})
.ModifyPagingOptions(pagingOptions =>
{
pagingOptions.IncludeTotalCount = true;
pagingOptions.RequirePagingBoundaries = false;
pagingOptions.DefaultPageSize = ApiController.DefaultPageSize;
pagingOptions.MaxPageSize = ApiController.MaximumPageSize;
})
.AddFiltering()
.AddSorting()
.AddHostTypes()
.AddErrorFilter<ErrorMessageFilter>()
.AddType<StandaloneNode>()
.AddType<LocalGateway>()
.AddType<RemoteGateway>()
.AddType<GraphQL.Types.UserName>()
.AddType<UnsignedIntType>()
.BindRuntimeType<Version, SemverType>()
.TryAddTypeInterceptor<RightsTypeInterceptor>()
.AddQueryType<Query>()
.AddMutationType<Mutation>()
.AddSubscriptionType<Subscription>();
void AddTypedContext<TContext>()
where TContext : DatabaseContext
@@ -158,6 +158,9 @@ namespace Tgstation.Server.Tests.Live
"Telemetry:DisableVersionReporting=true",
};
if (MultiServerClient.UseGraphQL)
args.Add("Internal:EnableGraphQL=true");
swarmArgs = new List<string>();
if (swarmConfiguration != null)
{
@@ -28,7 +28,7 @@ namespace Tgstation.Server.Tests.Live
public ValueTask DisposeAsync()
=> ValueTaskExtensions.WhenAll(
RestClient.DisposeAsync(),
GraphQLClient.DisposeAsync());
GraphQLClient?.DisposeAsync() ?? ValueTask.CompletedTask);
public ValueTask Execute(
Func<IRestServerClient, ValueTask> restAction,
@@ -48,6 +48,11 @@ namespace Tgstation.Server.Tests.Live
where TGraphQLResult : class
{
var restTask = restAction(RestClient);
if (!UseGraphQL)
{
return (await restTask, null);
}
var graphQLResult = await GraphQLClient.RunOperation(graphQLAction, cancellationToken);
graphQLResult.EnsureNoErrors();
@@ -60,6 +65,6 @@ namespace Tgstation.Server.Tests.Live
}
public ValueTask<IDisposable> Subscribe<TResultData>(Func<IGraphQLClient, IObservable<IOperationResult<TResultData>>> operationExecutor, IObserver<IOperationResult<TResultData>> observer, CancellationToken cancellationToken) where TResultData : class
=> GraphQLClient.Subscribe(operationExecutor, observer, cancellationToken);
=> GraphQLClient?.Subscribe(operationExecutor, observer, cancellationToken) ?? ValueTask.FromResult<IDisposable>(new CancellationTokenSource());
}
}
@@ -457,6 +457,9 @@ namespace Tgstation.Server.Tests.Live
static async Task TestGraphQLLogin(IRestServerClientFactory clientFactory, IRestServerClient restClient, CancellationToken cancellationToken)
{
if (!MultiServerClient.UseGraphQL)
return;
await using var gqlClient = new GraphQLServerClientFactory(clientFactory).CreateUnauthenticated(restClient.Url);
var result = await gqlClient.RunOperation(client => client.Login.ExecuteAsync(cancellationToken), cancellationToken);
@@ -1372,12 +1372,13 @@ namespace Tgstation.Server.Tests.Live
var firstAdminRestClient = firstAdminMultiClient.RestClient;
await using (var tokenOnlyGraphQLClient = graphQLClientFactory.CreateFromToken(server.RootUrl, firstAdminRestClient.Token.Bearer))
{
// just testing auth works the same here
var result = await tokenOnlyGraphQLClient.RunOperation(client => client.ServerVersion.ExecuteAsync(cancellationToken), cancellationToken);
Assert.IsTrue(result.IsSuccessResult());
}
if (MultiServerClient.UseGraphQL)
await using (var tokenOnlyGraphQLClient = graphQLClientFactory.CreateFromToken(server.RootUrl, firstAdminRestClient.Token.Bearer))
{
// just testing auth works the same here
var result = await tokenOnlyGraphQLClient.RunOperation(client => client.ServerVersion.ExecuteAsync(cancellationToken), cancellationToken);
Assert.IsTrue(result.IsSuccessResult());
}
await using (var tokenOnlyRestClient = restClientFactory.CreateFromToken(server.RootUrl, firstAdminRestClient.Token))
{
@@ -1393,32 +1394,33 @@ namespace Tgstation.Server.Tests.Live
}
// basic graphql test, to be used everywhere eventually
await using (var unauthenticatedGraphQLClient = graphQLClientFactory.CreateUnauthenticated(server.RootUrl))
{
// check auth works as expected
var result = await unauthenticatedGraphQLClient.RunOperation(client => client.ServerVersion.ExecuteAsync(cancellationToken), cancellationToken);
Assert.IsTrue(result.IsErrorResult());
if (MultiServerClient.UseGraphQL)
await using (var unauthenticatedGraphQLClient = graphQLClientFactory.CreateUnauthenticated(server.RootUrl))
{
// check auth works as expected
var result = await unauthenticatedGraphQLClient.RunOperation(client => client.ServerVersion.ExecuteAsync(cancellationToken), cancellationToken);
Assert.IsTrue(result.IsErrorResult());
// test getting server info
var unAuthedMultiClient = new MultiServerClient(firstAdminRestClient, unauthenticatedGraphQLClient);
// test getting server info
var unAuthedMultiClient = new MultiServerClient(firstAdminRestClient, unauthenticatedGraphQLClient);
await unauthenticatedGraphQLClient.RunQueryEnsureNoErrors(
gqlClient => gqlClient.UnauthenticatedServerInformation.ExecuteAsync(cancellationToken),
cancellationToken);
await unauthenticatedGraphQLClient.RunQueryEnsureNoErrors(
gqlClient => gqlClient.UnauthenticatedServerInformation.ExecuteAsync(cancellationToken),
cancellationToken);
var testObserver = new HoldLastObserver<IOperationResult<ISessionInvalidationResult>>();
using var subscription = await unauthenticatedGraphQLClient.Subscribe(
gql => gql.SessionInvalidation.Watch(),
testObserver,
cancellationToken);
var testObserver = new HoldLastObserver<IOperationResult<ISessionInvalidationResult>>();
using var subscription = await unauthenticatedGraphQLClient.Subscribe(
gql => gql.SessionInvalidation.Watch(),
testObserver,
cancellationToken);
await Task.Delay(1000, cancellationToken);
await Task.Delay(1000, cancellationToken);
Assert.AreEqual(0U, testObserver.ErrorCount);
Assert.AreEqual(1U, testObserver.ResultCount);
Assert.IsTrue(testObserver.LastValue.IsAuthenticationError());
Assert.IsTrue(testObserver.Completed);
}
Assert.AreEqual(0U, testObserver.ErrorCount);
Assert.AreEqual(1U, testObserver.ResultCount);
Assert.IsTrue(testObserver.LastValue.IsAuthenticationError());
Assert.IsTrue(testObserver.Completed);
}
async ValueTask<MultiServerClient> CreateUserWithNoInstancePerms()
{
@@ -1477,9 +1479,10 @@ namespace Tgstation.Server.Tests.Live
if (!openDreamOnly)
{
// force a session refresh if necessary
await firstAdminMultiClient.GraphQLClient.RunQueryEnsureNoErrors(
gql => gql.ReadCurrentUser.ExecuteAsync(cancellationToken),
cancellationToken);
if (MultiServerClient.UseGraphQL)
await firstAdminMultiClient.GraphQLClient.RunQueryEnsureNoErrors(
gql => gql.ReadCurrentUser.ExecuteAsync(cancellationToken),
cancellationToken);
jobsHubTestTask = FailFast(await jobsHubTest.Run(cancellationToken)); // returns Task<Task>
var rootTest = FailFast(RawRequestTests.Run(restClientFactory, firstAdminRestClient, cancellationToken));
@@ -1610,14 +1613,19 @@ namespace Tgstation.Server.Tests.Live
initialSessionId = dd.SessionId.Value;
// force a session refresh if necessary
await firstAdminMultiClient.GraphQLClient.RunQueryEnsureNoErrors(
gql => gql.ReadCurrentUser.ExecuteAsync(cancellationToken),
cancellationToken);
if (MultiServerClient.UseGraphQL)
{
await firstAdminMultiClient.GraphQLClient.RunQueryEnsureNoErrors(
gql => gql.ReadCurrentUser.ExecuteAsync(cancellationToken),
cancellationToken);
restartSubscription = await firstAdminMultiClient.GraphQLClient.Subscribe(
gql => gql.SessionInvalidation.Watch(),
restartObserver,
cancellationToken);
restartSubscription = await firstAdminMultiClient.GraphQLClient.Subscribe(
gql => gql.SessionInvalidation.Watch(),
restartObserver,
cancellationToken);
}
else
restartSubscription = null;
try
{
@@ -1628,7 +1636,7 @@ namespace Tgstation.Server.Tests.Live
}
catch
{
restartSubscription.Dispose();
restartSubscription?.Dispose();
throw;
}
}
@@ -1638,15 +1646,18 @@ namespace Tgstation.Server.Tests.Live
await Task.WhenAny(serverTask, Task.Delay(TimeSpan.FromMinutes(1), cancellationToken));
Assert.IsTrue(serverTask.IsCompleted);
Assert.AreEqual(0U, restartObserver.ErrorCount);
Assert.AreEqual(1U, restartObserver.ResultCount);
restartObserver.LastValue.EnsureNoErrors();
Assert.IsTrue(restartObserver.Completed);
Assert.AreEqual(SessionInvalidationReason.ServerShutdown, restartObserver.LastValue.Data.SessionInvalidated);
if (MultiServerClient.UseGraphQL)
{
Assert.AreEqual(0U, restartObserver.ErrorCount);
Assert.AreEqual(1U, restartObserver.ResultCount);
restartObserver.LastValue.EnsureNoErrors();
Assert.IsTrue(restartObserver.Completed);
Assert.AreEqual(SessionInvalidationReason.ServerShutdown, restartObserver.LastValue.Data.SessionInvalidated);
}
}
finally
{
restartSubscription.Dispose();
restartSubscription?.Dispose();
}
// test the reattach message queueing
@@ -1930,11 +1941,13 @@ namespace Tgstation.Server.Tests.Live
password,
cancellationToken: cancellationToken);
using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
graphQLClientTask = graphQLClientFactory.CreateFromLogin(
url,
username,
password,
cancellationToken: cts.Token);
graphQLClientTask = MultiServerClient.UseGraphQL
? graphQLClientFactory.CreateFromLogin(
url,
username,
password,
cancellationToken: cts.Token)
: ValueTask.FromResult<IAuthenticatedGraphQLServerClient>(null);
IRestServerClient restClient;
try
@@ -48,6 +48,9 @@ namespace Tgstation.Server.Tests.Live
await TestPagination(cancellationToken);
if (!MultiServerClient.UseGraphQL)
return;
Assert.IsFalse(observer.Completed);
Assert.AreEqual(0U, observer.ErrorCount);