Skip to content

Commit

Permalink
Merge pull request #1968 from tgstation/FixGraphQLBS [TGSDeploy]
Browse files Browse the repository at this point in the history
Fix GraphQL Experimental Feature being required
  • Loading branch information
Cyberboss authored Oct 11, 2024
2 parents 664c3e4 + a1bf931 commit fd86f72
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 98 deletions.
1 change: 0 additions & 1 deletion .github/workflows/ci-pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}"
Expand Down
2 changes: 1 addition & 1 deletion build/Version.props
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
89 changes: 44 additions & 45 deletions src/Tgstation.Server.Host/Core/Application.cs
Original file line number Diff line number Diff line change
Expand Up @@ -295,55 +295,54 @@ void ConfigureNewtonsoftJsonSerializerSettingsForApi(JsonSerializerSettings sett
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 =>
{
options.EnableDefer = true;
})
.ModifyPagingOptions(pagingOptions =>
.AddMutationConventions()
.AddInMemorySubscriptions(
new SubscriptionOptions
{
pagingOptions.IncludeTotalCount = true;
pagingOptions.RequirePagingBoundaries = false;
pagingOptions.DefaultPageSize = ApiController.DefaultPageSize;
pagingOptions.MaxPageSize = ApiController.MaximumPageSize;
TopicBufferCapacity = 1024, // mainly so high for tests, not possible to DoS the server without authentication and some other access to generate messages
})
.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
Expand Down
3 changes: 3 additions & 0 deletions tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ public LiveTestingServer(SwarmConfiguration swarmConfiguration, bool enableOAuth
"Telemetry:DisableVersionReporting=true",
};

if (MultiServerClient.UseGraphQL)
args.Add("Internal:EnableGraphQL=true");

swarmArgs = new List<string>();
if (swarmConfiguration != null)
{
Expand Down
9 changes: 7 additions & 2 deletions tests/Tgstation.Server.Tests/Live/MultiServerClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public MultiServerClient(IRestServerClient restServerClient, IGraphQLServerClien
public ValueTask DisposeAsync()
=> ValueTaskExtensions.WhenAll(
RestClient.DisposeAsync(),
GraphQLClient.DisposeAsync());
GraphQLClient?.DisposeAsync() ?? ValueTask.CompletedTask);

public ValueTask Execute(
Func<IRestServerClient, ValueTask> restAction,
Expand All @@ -48,6 +48,11 @@ public ValueTask Execute(
where TGraphQLResult : class
{
var restTask = restAction(RestClient);
if (!UseGraphQL)
{
return (await restTask, null);
}

var graphQLResult = await GraphQLClient.RunOperation(graphQLAction, cancellationToken);

graphQLResult.EnsureNoErrors();
Expand All @@ -60,6 +65,6 @@ public ValueTask Execute(
}

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());
}
}
3 changes: 3 additions & 0 deletions tests/Tgstation.Server.Tests/Live/RawRequestTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,9 @@ await serverClient.Users.Update(new UserUpdateRequest

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);

Expand Down
111 changes: 62 additions & 49 deletions tests/Tgstation.Server.Tests/Live/TestLiveServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1372,12 +1372,13 @@ async Task TestTgsInternal(bool openDreamOnly, CancellationToken hardCancellatio

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))
{
Expand All @@ -1393,32 +1394,33 @@ async Task TestTgsInternal(bool openDreamOnly, CancellationToken hardCancellatio
}

// 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()
{
Expand Down Expand Up @@ -1477,9 +1479,10 @@ async Task FailFast(Task task)
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));
Expand Down Expand Up @@ -1610,14 +1613,19 @@ await FailFast(
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
{
Expand All @@ -1628,7 +1636,7 @@ await firstAdminMultiClient.GraphQLClient.RunQueryEnsureNoErrors(
}
catch
{
restartSubscription.Dispose();
restartSubscription?.Dispose();
throw;
}
}
Expand All @@ -1638,15 +1646,18 @@ await firstAdminMultiClient.GraphQLClient.RunQueryEnsureNoErrors(
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
Expand Down Expand Up @@ -1930,11 +1941,13 @@ async ValueTask<MultiServerClient> CreateClient(
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
Expand Down
3 changes: 3 additions & 0 deletions tests/Tgstation.Server.Tests/Live/UsersTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ await ValueTaskExtensions.WhenAll(

await TestPagination(cancellationToken);

if (!MultiServerClient.UseGraphQL)
return;

Assert.IsFalse(observer.Completed);
Assert.AreEqual(0U, observer.ErrorCount);

Expand Down

0 comments on commit fd86f72

Please sign in to comment.