mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-07-17 02:52:55 +01:00
Implement SxS GraphQL users tests
This commit is contained in:
+16
@@ -0,0 +1,16 @@
|
||||
mutation CreateSystemUserWithPermissionSet($systemIdentifier: String!) {
|
||||
createUserBySystemIDAndPermissionSet(
|
||||
input: { permissionSet: {}, systemIdentifier: $systemIdentifier }
|
||||
) {
|
||||
errors {
|
||||
... on ErrorMessageError {
|
||||
additionalData
|
||||
errorCode
|
||||
message
|
||||
}
|
||||
}
|
||||
user {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
mutation CreateUserFromOAuthConnection($name: String!, $oAuthConnections: [OAuthConnectionInput!]!) {
|
||||
createUserByOAuthAndPermissionSet(input: { name: $name, oAuthConnections: $oAuthConnections }) {
|
||||
errors {
|
||||
... on ErrorMessageError {
|
||||
additionalData
|
||||
errorCode
|
||||
message
|
||||
}
|
||||
}
|
||||
user {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
mutation CreateUserGroup($name: String!) {
|
||||
createUserGroup(input: { name: $name }) {
|
||||
userGroup {
|
||||
id
|
||||
name
|
||||
permissionSet {
|
||||
administrationRights {
|
||||
canChangeVersion
|
||||
canDownloadLogs
|
||||
canEditOwnOAuthConnections
|
||||
canEditOwnPassword
|
||||
canReadUsers
|
||||
canRestartHost
|
||||
canUploadVersion
|
||||
canWriteUsers
|
||||
}
|
||||
instanceManagerRights {
|
||||
canCreate
|
||||
canDelete
|
||||
canGrantPermissions
|
||||
canList
|
||||
canRead
|
||||
canRelocate
|
||||
canRename
|
||||
canSetAutoUpdate
|
||||
canSetChatBotLimit
|
||||
canSetConfiguration
|
||||
canSetOnline
|
||||
}
|
||||
}
|
||||
}
|
||||
errors {
|
||||
... on ErrorMessageError {
|
||||
additionalData
|
||||
errorCode
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
mutation CreateUserGroupWithInstanceListPerm($name: String!) {
|
||||
createUserGroup(input: { name: $name, permissionSet: { instanceManagerRights: { canList: true } } }) {
|
||||
userGroup {
|
||||
id
|
||||
name
|
||||
permissionSet {
|
||||
administrationRights {
|
||||
canChangeVersion
|
||||
canDownloadLogs
|
||||
canEditOwnOAuthConnections
|
||||
canEditOwnPassword
|
||||
canReadUsers
|
||||
canRestartHost
|
||||
canUploadVersion
|
||||
canWriteUsers
|
||||
}
|
||||
instanceManagerRights {
|
||||
canCreate
|
||||
canDelete
|
||||
canGrantPermissions
|
||||
canList
|
||||
canRead
|
||||
canRelocate
|
||||
canRename
|
||||
canSetAutoUpdate
|
||||
canSetChatBotLimit
|
||||
canSetConfiguration
|
||||
canSetOnline
|
||||
}
|
||||
}
|
||||
}
|
||||
errors {
|
||||
... on ErrorMessageError {
|
||||
additionalData
|
||||
errorCode
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
mutation CreateUserWithPassword($name: String!, $password: String!) {
|
||||
createUserByPasswordAndPermissionSet(input: { name: $name, password: $password }) {
|
||||
errors {
|
||||
... on ErrorMessageError {
|
||||
additionalData
|
||||
errorCode
|
||||
message
|
||||
}
|
||||
}
|
||||
user {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
mutation CreateUserWithPasswordSelectOAuthConnections($name: String!, $password: String!) {
|
||||
createUserByPasswordAndPermissionSet(input: { name: $name, password: $password }) {
|
||||
user {
|
||||
id
|
||||
oAuthConnections {
|
||||
externalUserId
|
||||
provider
|
||||
}
|
||||
}
|
||||
errors {
|
||||
... on ErrorMessageError {
|
||||
additionalData
|
||||
errorCode
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
mutation DeleteUserGroup($id: ID!) {
|
||||
deleteEmptyUserGroup(input: { id: $id }) {
|
||||
errors {
|
||||
... on ErrorMessageError {
|
||||
additionalData
|
||||
errorCode
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
mutation SetFullPermsOnUserGroup($id: ID!) {
|
||||
updateUserGroup(
|
||||
input: {
|
||||
id: $id
|
||||
newPermissionSet: {
|
||||
administrationRights: {
|
||||
canChangeVersion: true
|
||||
canDownloadLogs: true
|
||||
canEditOwnOAuthConnections: true
|
||||
canEditOwnPassword: true
|
||||
canReadUsers: true
|
||||
canWriteUsers: true
|
||||
canUploadVersion: true
|
||||
canRestartHost: true
|
||||
}
|
||||
instanceManagerRights: {
|
||||
canCreate: true
|
||||
canDelete: true
|
||||
canGrantPermissions: true
|
||||
canSetOnline: true
|
||||
canSetConfiguration: true
|
||||
canSetChatBotLimit: true
|
||||
canSetAutoUpdate: true
|
||||
canRename: true
|
||||
canRead: true
|
||||
canList: true
|
||||
canRelocate: true
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
userGroup {
|
||||
id
|
||||
name
|
||||
permissionSet {
|
||||
administrationRights {
|
||||
canChangeVersion
|
||||
canDownloadLogs
|
||||
canEditOwnOAuthConnections
|
||||
canEditOwnPassword
|
||||
canReadUsers
|
||||
canRestartHost
|
||||
canUploadVersion
|
||||
canWriteUsers
|
||||
}
|
||||
instanceManagerRights {
|
||||
canCreate
|
||||
canDelete
|
||||
canGrantPermissions
|
||||
canList
|
||||
canRead
|
||||
canRelocate
|
||||
canRename
|
||||
canSetAutoUpdate
|
||||
canSetChatBotLimit
|
||||
canSetConfiguration
|
||||
canSetOnline
|
||||
}
|
||||
}
|
||||
}
|
||||
errors {
|
||||
... on ErrorMessageError {
|
||||
additionalData
|
||||
errorCode
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
mutation SetUserGroup($id: ID!, $newGroupId: ID!) {
|
||||
updateUserSetGroup(input: { id: $id, newGroupId: $newGroupId }) {
|
||||
errors {
|
||||
... on ErrorMessageError {
|
||||
additionalData
|
||||
errorCode
|
||||
message
|
||||
}
|
||||
}
|
||||
user {
|
||||
ownedPermissionSet {
|
||||
instanceManagerRights {
|
||||
canCreate
|
||||
canDelete
|
||||
canGrantPermissions
|
||||
canList
|
||||
canRead
|
||||
canRelocate
|
||||
canRename
|
||||
canSetAutoUpdate
|
||||
canSetChatBotLimit
|
||||
canSetConfiguration
|
||||
canSetOnline
|
||||
}
|
||||
administrationRights {
|
||||
canChangeVersion
|
||||
canDownloadLogs
|
||||
canEditOwnOAuthConnections
|
||||
canEditOwnPassword
|
||||
canReadUsers
|
||||
canRestartHost
|
||||
canUploadVersion
|
||||
canWriteUsers
|
||||
}
|
||||
}
|
||||
group {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
mutation SetUserOAuthConnections($id: ID!, $newOAuthConnections: [OAuthConnectionInput!]!) {
|
||||
updateUser(
|
||||
input: { id: $id, newOAuthConnections: $newOAuthConnections }
|
||||
) {
|
||||
user {
|
||||
canonicalName
|
||||
createdAt
|
||||
enabled
|
||||
id
|
||||
name
|
||||
systemIdentifier
|
||||
oAuthConnections {
|
||||
externalUserId
|
||||
provider
|
||||
}
|
||||
}
|
||||
errors {
|
||||
... on ErrorMessageError {
|
||||
additionalData
|
||||
errorCode
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
mutation SetUserPermissionSet($id: ID!, $permissionSet: PermissionSetInput!) {
|
||||
updateUserSetOwnedPermissionSet(input: { newPermissionSet: $permissionSet, id: $id }) {
|
||||
errors {
|
||||
... on ErrorMessageError {
|
||||
additionalData
|
||||
errorCode
|
||||
message
|
||||
}
|
||||
}
|
||||
user {
|
||||
effectivePermissionSet {
|
||||
administrationRights {
|
||||
canChangeVersion
|
||||
canDownloadLogs
|
||||
canEditOwnOAuthConnections
|
||||
canEditOwnPassword
|
||||
canReadUsers
|
||||
canRestartHost
|
||||
canUploadVersion
|
||||
canWriteUsers
|
||||
}
|
||||
instanceManagerRights {
|
||||
canCreate
|
||||
canDelete
|
||||
canGrantPermissions
|
||||
canList
|
||||
canRead
|
||||
canRelocate
|
||||
canRename
|
||||
canSetAutoUpdate
|
||||
canSetChatBotLimit
|
||||
canSetConfiguration
|
||||
canSetOnline
|
||||
}
|
||||
}
|
||||
ownedPermissionSet {
|
||||
administrationRights {
|
||||
canChangeVersion
|
||||
canDownloadLogs
|
||||
canEditOwnOAuthConnections
|
||||
canEditOwnPassword
|
||||
canReadUsers
|
||||
canRestartHost
|
||||
canUploadVersion
|
||||
canWriteUsers
|
||||
}
|
||||
instanceManagerRights {
|
||||
canCreate
|
||||
canDelete
|
||||
canGrantPermissions
|
||||
canList
|
||||
canRead
|
||||
canRelocate
|
||||
canRename
|
||||
canSetAutoUpdate
|
||||
canSetChatBotLimit
|
||||
canSetConfiguration
|
||||
canSetOnline
|
||||
}
|
||||
}
|
||||
group {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
mutation UpdateUserOAuthConnections($id: ID!, $newOAuthConnections: [OAuthConnectionInput!]) {
|
||||
updateUser(input: { id: $id, newOAuthConnections: $newOAuthConnections }) {
|
||||
user {
|
||||
id
|
||||
oAuthConnections {
|
||||
externalUserId
|
||||
provider
|
||||
}
|
||||
}
|
||||
errors {
|
||||
... on ErrorMessageError {
|
||||
additionalData
|
||||
errorCode
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
query GetSomeGroupInfo($id: ID!) {
|
||||
swarm {
|
||||
users {
|
||||
groups {
|
||||
byId(id: $id) {
|
||||
permissionSet {
|
||||
instanceManagerRights {
|
||||
canCreate
|
||||
canDelete
|
||||
canGrantPermissions
|
||||
canList
|
||||
canRead
|
||||
canRelocate
|
||||
canRename
|
||||
canSetAutoUpdate
|
||||
canSetChatBotLimit
|
||||
canSetConfiguration
|
||||
canSetOnline
|
||||
}
|
||||
administrationRights {
|
||||
canChangeVersion
|
||||
canDownloadLogs
|
||||
canEditOwnOAuthConnections
|
||||
canEditOwnPassword
|
||||
canReadUsers
|
||||
canRestartHost
|
||||
canUploadVersion
|
||||
canWriteUsers
|
||||
}
|
||||
}
|
||||
queryableUsersByGroup(first: 1) {
|
||||
totalCount
|
||||
nodes {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
query GetUserById($id: ID!) {
|
||||
swarm {
|
||||
users {
|
||||
byId(id: $id) {
|
||||
canonicalName
|
||||
createdAt
|
||||
enabled
|
||||
id
|
||||
name
|
||||
systemIdentifier
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
query GetUserNameByNodeId($id: ID!) {
|
||||
node(id: $id) {
|
||||
... on UserName {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
query ListUserGroups {
|
||||
swarm {
|
||||
users {
|
||||
groups {
|
||||
queryableGroups {
|
||||
totalCount
|
||||
nodes {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
query ListUsers {
|
||||
swarm {
|
||||
users {
|
||||
queryableUsers {
|
||||
nodes {
|
||||
id
|
||||
}
|
||||
totalCount
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
query PageUserIds($first: Int, $after: String) {
|
||||
swarm {
|
||||
users {
|
||||
queryableUsers(first: $first, after: $after) {
|
||||
pageInfo {
|
||||
endCursor
|
||||
hasNextPage
|
||||
}
|
||||
totalCount
|
||||
nodes {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
query ReadCurrentUser {
|
||||
swarm {
|
||||
users {
|
||||
current {
|
||||
canonicalName
|
||||
createdAt
|
||||
enabled
|
||||
id
|
||||
name
|
||||
systemIdentifier
|
||||
group {
|
||||
id
|
||||
name
|
||||
}
|
||||
oAuthConnections {
|
||||
externalUserId
|
||||
provider
|
||||
}
|
||||
effectivePermissionSet {
|
||||
administrationRights {
|
||||
canChangeVersion
|
||||
canDownloadLogs
|
||||
canEditOwnOAuthConnections
|
||||
canEditOwnPassword
|
||||
canReadUsers
|
||||
canRestartHost
|
||||
canUploadVersion
|
||||
canWriteUsers
|
||||
}
|
||||
instanceManagerRights {
|
||||
canCreate
|
||||
canDelete
|
||||
canGrantPermissions
|
||||
canList
|
||||
canRead
|
||||
canRelocate
|
||||
canRename
|
||||
canSetAutoUpdate
|
||||
canSetChatBotLimit
|
||||
canSetConfiguration
|
||||
canSetOnline
|
||||
}
|
||||
}
|
||||
createdBy {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,15 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
using StrawberryShake;
|
||||
|
||||
using Tgstation.Server.Client;
|
||||
using Tgstation.Server.Client.GraphQL;
|
||||
|
||||
namespace Tgstation.Server.Tests.Live
|
||||
{
|
||||
@@ -19,7 +25,7 @@ namespace Tgstation.Server.Tests.Live
|
||||
/// <param name="action">A <see cref="Func{TResult}"/> resulting in a <see cref="Task"/>.</param>
|
||||
/// <param name="expectedErrorCode">The expected <see cref="ApiException.ErrorCode"/>.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the running operation,</returns>
|
||||
public static async ValueTask ThrowsException<TApiException>(Func<ValueTask> action, ErrorCode? expectedErrorCode = null)
|
||||
public static async ValueTask ThrowsException<TApiException>(Func<ValueTask> action, Api.Models.ErrorCode? expectedErrorCode = null)
|
||||
where TApiException : ApiException
|
||||
{
|
||||
try
|
||||
@@ -43,7 +49,7 @@ namespace Tgstation.Server.Tests.Live
|
||||
/// <param name="action">A <see cref="Func{TResult}"/> resulting in a <see cref="Task"/>.</param>
|
||||
/// <param name="expectedErrorCode">The expected <see cref="ApiException.ErrorCode"/>.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the running operation,</returns>
|
||||
public static async ValueTask ThrowsException<TApiException, TResult>(Func<ValueTask<TResult>> action, ErrorCode? expectedErrorCode = null)
|
||||
public static async ValueTask ThrowsException<TApiException, TResult>(Func<ValueTask<TResult>> action, Api.Models.ErrorCode? expectedErrorCode = null)
|
||||
where TApiException : ApiException
|
||||
{
|
||||
try
|
||||
@@ -58,5 +64,25 @@ namespace Tgstation.Server.Tests.Live
|
||||
|
||||
Assert.Fail($"Expected exception {typeof(TApiException)}!");
|
||||
}
|
||||
|
||||
public static async ValueTask OperationFails<TResultData, TPayload>(
|
||||
IGraphQLServerClient client,
|
||||
Func<IGraphQLClient, Task<IOperationResult<TResultData>>> operationInvoker,
|
||||
Func<TResultData, TPayload> payloadSelector,
|
||||
Client.GraphQL.ErrorCode expectedErrorCode,
|
||||
CancellationToken cancellationToken)
|
||||
where TResultData : class
|
||||
{
|
||||
var operationResult = await client.RunOperation(operationInvoker, cancellationToken);
|
||||
operationResult.EnsureNoErrors();
|
||||
|
||||
var payload = payloadSelector(operationResult.Data);
|
||||
|
||||
var payloadErrors = (IEnumerable<object>)payload.GetType().GetProperty("Errors").GetValue(payload);
|
||||
var error = payloadErrors.Single();
|
||||
|
||||
var errorCode = (ErrorCode)error.GetType().GetProperty("ErrorCode").GetValue(error);
|
||||
Assert.AreEqual(expectedErrorCode, errorCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
using StrawberryShake;
|
||||
|
||||
using Tgstation.Server.Client.GraphQL;
|
||||
|
||||
namespace Tgstation.Server.Tests.Live
|
||||
{
|
||||
static class GraphQLServerClientExtensions
|
||||
{
|
||||
public static async ValueTask<TResultData> RunQueryEnsureNoErrors<TResultData>(
|
||||
this IGraphQLServerClient serverClient,
|
||||
Func<IGraphQLClient, Task<IOperationResult<TResultData>>> operationExecutor,
|
||||
CancellationToken cancellationToken)
|
||||
where TResultData : class
|
||||
{
|
||||
var result = await serverClient.RunOperation(operationExecutor, cancellationToken);
|
||||
result.EnsureNoErrors();
|
||||
return result.Data;
|
||||
}
|
||||
|
||||
public static async ValueTask<TPayload> RunMutationEnsureNoErrors<TResultData, TPayload>(
|
||||
this IGraphQLServerClient serverClient,
|
||||
Func<IGraphQLClient, Task<IOperationResult<TResultData>>> operationExecutor,
|
||||
Func<TResultData, TPayload> payloadSelector,
|
||||
CancellationToken cancellationToken)
|
||||
where TResultData : class
|
||||
{
|
||||
var result = await serverClient.RunOperation(operationExecutor, cancellationToken);
|
||||
result.EnsureNoErrors();
|
||||
var data = payloadSelector(result.Data);
|
||||
var errorsObject = data.GetType().GetProperty("Errors").GetValue(data);
|
||||
if (errorsObject != null)
|
||||
{
|
||||
var errorsCount = (int)errorsObject.GetType().GetProperty("Count").GetValue(errorsObject);
|
||||
|
||||
Assert.AreEqual(0, errorsCount);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using StrawberryShake;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System;
|
||||
using Tgstation.Server.Client.GraphQL;
|
||||
using Tgstation.Server.Client;
|
||||
|
||||
namespace Tgstation.Server.Tests.Live
|
||||
{
|
||||
interface IMultiServerClient
|
||||
{
|
||||
ValueTask Execute(
|
||||
Func<IRestServerClient, ValueTask> restAction,
|
||||
Func<IGraphQLServerClient, ValueTask> graphQLAction);
|
||||
|
||||
ValueTask<(TRestResult, TGraphQLResult)> ExecuteReadOnlyConfirmEquivalence<TRestResult, TGraphQLResult>(
|
||||
Func<IRestServerClient, ValueTask<TRestResult>> restAction,
|
||||
Func<IGraphQLClient, Task<IOperationResult<TGraphQLResult>>> graphQLAction,
|
||||
Func<TRestResult, TGraphQLResult, bool> comparison,
|
||||
CancellationToken cancellationToken)
|
||||
where TGraphQLResult : class;
|
||||
}
|
||||
}
|
||||
@@ -34,10 +34,10 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
|
||||
long? permlessPsId;
|
||||
|
||||
public JobsHubTests(IRestServerClient permedUser, IRestServerClient permlessUser)
|
||||
public JobsHubTests(MultiServerClient permedUser, MultiServerClient permlessUser)
|
||||
{
|
||||
this.permedUser = permedUser;
|
||||
this.permlessUser = permlessUser;
|
||||
this.permedUser = permedUser.RestClient;
|
||||
this.permlessUser = permlessUser.RestClient;
|
||||
|
||||
Assert.AreNotSame(permedUser, permlessUser);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -12,7 +12,7 @@ using Tgstation.Server.Common.Extensions;
|
||||
|
||||
namespace Tgstation.Server.Tests.Live
|
||||
{
|
||||
sealed class MultiServerClient : IAsyncDisposable
|
||||
sealed class MultiServerClient : IMultiServerClient, IAsyncDisposable
|
||||
{
|
||||
public IRestServerClient RestClient { get; }
|
||||
public IGraphQLServerClient GraphQLClient { get; }
|
||||
@@ -40,7 +40,7 @@ namespace Tgstation.Server.Tests.Live
|
||||
return restAction(RestClient);
|
||||
}
|
||||
|
||||
public async ValueTask ExecuteReadOnlyConfirmEquivalence<TRestResult, TGraphQLResult>(
|
||||
public async ValueTask<(TRestResult, TGraphQLResult)> ExecuteReadOnlyConfirmEquivalence<TRestResult, TGraphQLResult>(
|
||||
Func<IRestServerClient, ValueTask<TRestResult>> restAction,
|
||||
Func<IGraphQLClient, Task<IOperationResult<TGraphQLResult>>> graphQLAction,
|
||||
Func<TRestResult, TGraphQLResult, bool> comparison,
|
||||
@@ -50,8 +50,13 @@ namespace Tgstation.Server.Tests.Live
|
||||
var restTask = restAction(RestClient);
|
||||
var graphQLResult = await GraphQLClient.RunOperation(graphQLAction, cancellationToken);
|
||||
|
||||
graphQLResult.EnsureNoErrors();
|
||||
|
||||
var restResult = await restTask;
|
||||
Assert.IsTrue(comparison(restResult, graphQLResult.Data), "REST/GraphQL results differ!");
|
||||
var comparisonResult = comparison(restResult, graphQLResult.Data);
|
||||
Assert.IsTrue(comparisonResult, "REST/GraphQL results differ!");
|
||||
|
||||
return (restResult, graphQLResult.Data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
@@ -1379,20 +1379,25 @@ namespace Tgstation.Server.Tests.Live
|
||||
await unAuthedMultiClient.ExecuteReadOnlyConfirmEquivalence(
|
||||
restClient => restClient.ServerInformation(cancellationToken),
|
||||
gqlClient => gqlClient.UnauthenticatedServerInformation.ExecuteAsync(cancellationToken),
|
||||
(restServerInfo, gqlServerInfo) => restServerInfo.ApiVersion.Major == gqlServerInfo.Swarm.CurrentNode.Gateway.Information.MajorApiVersion
|
||||
&& (restServerInfo.OAuthProviderInfos == gqlServerInfo.Swarm.CurrentNode.Gateway.Information.OAuthProviderInfos
|
||||
|| restServerInfo.OAuthProviderInfos.All(kvp =>
|
||||
{
|
||||
var info = gqlServerInfo.Swarm.CurrentNode.Gateway.Information.OAuthProviderInfos.FirstOrDefault(x => (int)x.Key == (int)kvp.Key);
|
||||
return info != null
|
||||
&& info.Value.ServerUrl == kvp.Value.ServerUrl
|
||||
&& info.Value.ClientId == kvp.Value.ClientId
|
||||
&& info.Value.RedirectUri == kvp.Value.RedirectUri;
|
||||
})),
|
||||
(restServerInfo, gqlServerInfo) =>
|
||||
{
|
||||
var result = restServerInfo.ApiVersion.Major == gqlServerInfo.Swarm.CurrentNode.Gateway.Information.MajorApiVersion
|
||||
&& (restServerInfo.OAuthProviderInfos == gqlServerInfo.Swarm.CurrentNode.Gateway.Information.OAuthProviderInfos
|
||||
|| restServerInfo.OAuthProviderInfos.All(kvp =>
|
||||
{
|
||||
var info = gqlServerInfo.Swarm.CurrentNode.Gateway.Information.OAuthProviderInfos.FirstOrDefault(x => (int)x.Key == (int)kvp.Key);
|
||||
return info != null
|
||||
&& info.Value.ServerUrl == kvp.Value.ServerUrl
|
||||
&& info.Value.ClientId == kvp.Value.ClientId
|
||||
&& info.Value.RedirectUri == kvp.Value.RedirectUri;
|
||||
}));
|
||||
|
||||
return result;
|
||||
},
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
async ValueTask<IRestServerClient> CreateUserWithNoInstancePerms()
|
||||
async ValueTask<MultiServerClient> CreateUserWithNoInstancePerms()
|
||||
{
|
||||
var createRequest = new UserCreateRequest()
|
||||
{
|
||||
@@ -1408,10 +1413,10 @@ namespace Tgstation.Server.Tests.Live
|
||||
var user = await firstAdminRestClient.Users.Create(createRequest, cancellationToken);
|
||||
Assert.IsTrue(user.Enabled);
|
||||
|
||||
return await restClientFactory.CreateFromLogin(server.RootUrl, createRequest.Name, createRequest.Password, cancellationToken: cancellationToken);
|
||||
return await CreateClient(server.RootUrl, createRequest.Name, createRequest.Password, false, cancellationToken);
|
||||
}
|
||||
|
||||
var jobsHubTest = new JobsHubTests(firstAdminRestClient, await CreateUserWithNoInstancePerms());
|
||||
var jobsHubTest = new JobsHubTests(firstAdminMultiClient, await CreateUserWithNoInstancePerms());
|
||||
Task jobsHubTestTask;
|
||||
{
|
||||
if (server.DumpOpenApiSpecpath)
|
||||
@@ -1449,7 +1454,7 @@ namespace Tgstation.Server.Tests.Live
|
||||
jobsHubTestTask = FailFast(await jobsHubTest.Run(cancellationToken)); // returns Task<Task>
|
||||
var rootTest = FailFast(RawRequestTests.Run(restClientFactory, firstAdminRestClient, cancellationToken));
|
||||
var adminTest = FailFast(new AdministrationTest(firstAdminRestClient.Administration).Run(cancellationToken));
|
||||
var usersTest = FailFast(new UsersTest(firstAdminRestClient).Run(cancellationToken));
|
||||
var usersTest = FailFast(new UsersTest(firstAdminMultiClient).Run(cancellationToken).AsTask());
|
||||
|
||||
var instanceManagerTest = new InstanceManagerTest(firstAdminRestClient, server.Directory);
|
||||
var compatInstanceTask = instanceManagerTest.CreateTestInstance("CompatTestsInstance", cancellationToken);
|
||||
@@ -1836,7 +1841,15 @@ namespace Tgstation.Server.Tests.Live
|
||||
await serverTask;
|
||||
}
|
||||
|
||||
async ValueTask<MultiServerClient> CreateAdminClient(Uri url, CancellationToken cancellationToken)
|
||||
ValueTask<MultiServerClient> CreateAdminClient(Uri url, CancellationToken cancellationToken)
|
||||
=> CreateClient(url, DefaultCredentials.AdminUserName, DefaultCredentials.DefaultAdminUserPassword, true, cancellationToken);
|
||||
|
||||
async ValueTask<MultiServerClient> CreateClient(
|
||||
Uri url,
|
||||
string username,
|
||||
string password,
|
||||
bool retry,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
url = new Uri(url.ToString().Replace(Routes.ApiRoot, String.Empty));
|
||||
var giveUpAt = DateTimeOffset.UtcNow.AddMinutes(2);
|
||||
@@ -1850,14 +1863,14 @@ namespace Tgstation.Server.Tests.Live
|
||||
|
||||
restClientTask = restClientFactory.CreateFromLogin(
|
||||
url,
|
||||
DefaultCredentials.AdminUserName,
|
||||
DefaultCredentials.DefaultAdminUserPassword,
|
||||
username,
|
||||
password,
|
||||
cancellationToken: cancellationToken);
|
||||
using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
||||
graphQLClientTask = graphQLClientFactory.CreateFromLogin(
|
||||
url,
|
||||
DefaultCredentials.AdminUserName,
|
||||
DefaultCredentials.DefaultAdminUserPassword,
|
||||
username,
|
||||
password,
|
||||
cancellationToken: cts.Token);
|
||||
|
||||
IRestServerClient restClient;
|
||||
@@ -1898,14 +1911,14 @@ namespace Tgstation.Server.Tests.Live
|
||||
catch (HttpRequestException)
|
||||
{
|
||||
//migrating, to be expected
|
||||
if (DateTimeOffset.UtcNow > giveUpAt)
|
||||
if (DateTimeOffset.UtcNow > giveUpAt || !retry)
|
||||
throw;
|
||||
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
|
||||
}
|
||||
catch (ServiceUnavailableException)
|
||||
{
|
||||
// migrating, to be expected
|
||||
if (DateTimeOffset.UtcNow > giveUpAt)
|
||||
if (DateTimeOffset.UtcNow > giveUpAt || !retry)
|
||||
throw;
|
||||
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Elastic.CommonSchema;
|
||||
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
using StrawberryShake;
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
@@ -10,23 +16,25 @@ using Tgstation.Server.Api.Models.Request;
|
||||
using Tgstation.Server.Api.Models.Response;
|
||||
using Tgstation.Server.Api.Rights;
|
||||
using Tgstation.Server.Client;
|
||||
using Tgstation.Server.Client.GraphQL;
|
||||
using Tgstation.Server.Common.Extensions;
|
||||
using Tgstation.Server.Host.Controllers;
|
||||
using Tgstation.Server.Host.System;
|
||||
|
||||
namespace Tgstation.Server.Tests.Live
|
||||
{
|
||||
sealed class UsersTest
|
||||
{
|
||||
readonly IRestServerClient serverClient;
|
||||
readonly IMultiServerClient serverClient;
|
||||
|
||||
public UsersTest(IRestServerClient serverClient)
|
||||
public UsersTest(IMultiServerClient serverClient)
|
||||
{
|
||||
this.serverClient = serverClient ?? throw new ArgumentNullException(nameof(serverClient));
|
||||
}
|
||||
|
||||
public async Task Run(CancellationToken cancellationToken)
|
||||
public async ValueTask Run(CancellationToken cancellationToken)
|
||||
{
|
||||
await Task.WhenAll(
|
||||
await ValueTaskExtensions.WhenAll(
|
||||
BasicTests(cancellationToken),
|
||||
TestCreateSysUser(cancellationToken),
|
||||
TestSpamCreation(cancellationToken));
|
||||
@@ -34,214 +42,525 @@ namespace Tgstation.Server.Tests.Live
|
||||
await TestPagination(cancellationToken);
|
||||
}
|
||||
|
||||
async Task BasicTests(CancellationToken cancellationToken)
|
||||
async ValueTask BasicTests(CancellationToken cancellationToken)
|
||||
{
|
||||
var user = await serverClient.Users.Read(cancellationToken);
|
||||
Assert.IsNotNull(user);
|
||||
Assert.AreEqual("Admin", user.Name);
|
||||
Assert.IsNull(user.SystemIdentifier);
|
||||
Assert.AreEqual(true, user.Enabled);
|
||||
Assert.IsNotNull(user.OAuthConnections);
|
||||
Assert.IsNotNull(user.PermissionSet);
|
||||
Assert.IsNotNull(user.PermissionSet.Id);
|
||||
Assert.IsNotNull(user.PermissionSet.InstanceManagerRights);
|
||||
Assert.IsNotNull(user.PermissionSet.AdministrationRights);
|
||||
var (restUser, gqlUser) = await serverClient.ExecuteReadOnlyConfirmEquivalence(
|
||||
client => client.Users.Read(cancellationToken),
|
||||
client => client.ReadCurrentUser.ExecuteAsync(cancellationToken),
|
||||
(restResult, graphQLResult) =>
|
||||
{
|
||||
var gqlUser = graphQLResult.Swarm.Users.Current;
|
||||
return restResult.Enabled == gqlUser.Enabled
|
||||
&& restResult.Name == gqlUser.Name
|
||||
&& (restResult.CreatedAt.Value.Ticks / 1000000) == (gqlUser.CreatedAt.Ticks / 1000000)
|
||||
&& restResult.SystemIdentifier == gqlUser.SystemIdentifier
|
||||
&& restResult.CreatedBy.Name == gqlUser.CreatedBy.Name;
|
||||
},
|
||||
cancellationToken);
|
||||
|
||||
var systemUser = user.CreatedBy;
|
||||
Assert.IsNotNull(restUser);
|
||||
Assert.AreEqual("Admin", restUser.Name);
|
||||
Assert.IsNull(restUser.SystemIdentifier);
|
||||
Assert.AreEqual(true, restUser.Enabled);
|
||||
Assert.IsNotNull(restUser.OAuthConnections);
|
||||
Assert.IsNotNull(restUser.PermissionSet);
|
||||
Assert.IsNotNull(restUser.PermissionSet.Id);
|
||||
Assert.IsNotNull(restUser.PermissionSet.InstanceManagerRights);
|
||||
Assert.IsNotNull(restUser.PermissionSet.AdministrationRights);
|
||||
|
||||
var systemUser = restUser.CreatedBy;
|
||||
Assert.IsNotNull(systemUser);
|
||||
Assert.AreEqual("TGS", systemUser.Name);
|
||||
|
||||
var users = await serverClient.Users.List(null, cancellationToken);
|
||||
Assert.IsTrue(users.Count > 0);
|
||||
Assert.IsFalse(users.Any(x => x.Id == systemUser.Id));
|
||||
|
||||
await ApiAssert.ThrowsException<InsufficientPermissionsException, UserResponse>(() => serverClient.Users.GetId(systemUser, cancellationToken));
|
||||
await ApiAssert.ThrowsException<InsufficientPermissionsException, UserResponse>(() => serverClient.Users.Update(new UserUpdateRequest
|
||||
{
|
||||
Id = systemUser.Id
|
||||
}, cancellationToken));
|
||||
|
||||
var sampleOAuthConnections = new List<OAuthConnection>
|
||||
{
|
||||
new OAuthConnection
|
||||
await serverClient.Execute(
|
||||
async client =>
|
||||
{
|
||||
ExternalUserId = "asdfasdf",
|
||||
Provider = OAuthProvider.Discord
|
||||
}
|
||||
};
|
||||
await ApiAssert.ThrowsException<ApiConflictException, UserResponse>(() => serverClient.Users.Update(new UserUpdateRequest
|
||||
{
|
||||
Id = user.Id,
|
||||
OAuthConnections = sampleOAuthConnections
|
||||
}, cancellationToken), ErrorCode.AdminUserCannotOAuth);
|
||||
var users = await client.Users.List(null, cancellationToken);
|
||||
Assert.IsTrue(users.Count > 0);
|
||||
Assert.IsFalse(users.Any(x => x.Id == systemUser.Id));
|
||||
|
||||
var testUser = await serverClient.Users.Create(
|
||||
new UserCreateRequest
|
||||
{
|
||||
Name = $"BasicTestUser",
|
||||
Password = "asdfasdjfhauwiehruiy273894234jhndjkwh"
|
||||
await ApiAssert.ThrowsException<InsufficientPermissionsException, UserResponse>(() => client.Users.GetId(systemUser, cancellationToken));
|
||||
await ApiAssert.ThrowsException<InsufficientPermissionsException, UserResponse>(() => client.Users.Update(new UserUpdateRequest
|
||||
{
|
||||
Id = systemUser.Id
|
||||
}, cancellationToken));
|
||||
|
||||
var sampleOAuthConnections = new List<OAuthConnection>
|
||||
{
|
||||
new()
|
||||
{
|
||||
ExternalUserId = "asdfasdf",
|
||||
Provider = Api.Models.OAuthProvider.Discord
|
||||
}
|
||||
};
|
||||
|
||||
await ApiAssert.ThrowsException<ApiConflictException, UserResponse>(() => client.Users.Update(new UserUpdateRequest
|
||||
{
|
||||
Id = restUser.Id,
|
||||
OAuthConnections = sampleOAuthConnections
|
||||
}, cancellationToken), Api.Models.ErrorCode.AdminUserCannotOAuth);
|
||||
|
||||
var testUser = await client.Users.Create(
|
||||
new UserCreateRequest
|
||||
{
|
||||
Name = $"BasicTestUser",
|
||||
Password = "asdfasdjfhauwiehruiy273894234jhndjkwh"
|
||||
},
|
||||
cancellationToken);
|
||||
|
||||
Assert.IsNotNull(testUser.OAuthConnections);
|
||||
testUser = await client.Users.Update(
|
||||
new UserUpdateRequest
|
||||
{
|
||||
Id = testUser.Id,
|
||||
OAuthConnections = sampleOAuthConnections
|
||||
},
|
||||
cancellationToken);
|
||||
|
||||
Assert.AreEqual(1, testUser.OAuthConnections.Count);
|
||||
Assert.AreEqual(sampleOAuthConnections.First().ExternalUserId, testUser.OAuthConnections.First().ExternalUserId);
|
||||
Assert.AreEqual(sampleOAuthConnections.First().Provider, testUser.OAuthConnections.First().Provider);
|
||||
|
||||
var group = await client.Groups.Create(
|
||||
new UserGroupCreateRequest
|
||||
{
|
||||
Name = "TestGroup"
|
||||
},
|
||||
cancellationToken);
|
||||
Assert.AreEqual(group.Name, "TestGroup");
|
||||
Assert.IsNotNull(group.PermissionSet);
|
||||
Assert.IsNotNull(group.PermissionSet.Id);
|
||||
Assert.AreEqual(AdministrationRights.None, group.PermissionSet.AdministrationRights);
|
||||
Assert.AreEqual(InstanceManagerRights.None, group.PermissionSet.InstanceManagerRights);
|
||||
|
||||
var group2 = await client.Groups.Create(new UserGroupCreateRequest
|
||||
{
|
||||
Name = "TestGroup2",
|
||||
PermissionSet = new PermissionSet
|
||||
{
|
||||
InstanceManagerRights = InstanceManagerRights.List
|
||||
}
|
||||
}, cancellationToken);
|
||||
Assert.AreEqual(AdministrationRights.None, group2.PermissionSet.AdministrationRights);
|
||||
Assert.AreEqual(InstanceManagerRights.List, group2.PermissionSet.InstanceManagerRights);
|
||||
|
||||
var groups = await client.Groups.List(null, cancellationToken);
|
||||
Assert.AreEqual(2, groups.Count);
|
||||
|
||||
foreach (var igroup in groups)
|
||||
{
|
||||
Assert.IsNotNull(igroup.Users);
|
||||
Assert.IsNotNull(igroup.PermissionSet);
|
||||
}
|
||||
|
||||
await client.Groups.Delete(group2, cancellationToken);
|
||||
|
||||
groups = await client.Groups.List(null, cancellationToken);
|
||||
Assert.AreEqual(1, groups.Count);
|
||||
|
||||
group = await client.Groups.Update(new UserGroupUpdateRequest
|
||||
{
|
||||
Id = groups[0].Id,
|
||||
PermissionSet = new PermissionSet
|
||||
{
|
||||
InstanceManagerRights = RightsHelper.AllRights<InstanceManagerRights>(),
|
||||
AdministrationRights = RightsHelper.AllRights<AdministrationRights>(),
|
||||
}
|
||||
}, cancellationToken);
|
||||
|
||||
Assert.AreEqual(RightsHelper.AllRights<AdministrationRights>(), group.PermissionSet.AdministrationRights);
|
||||
Assert.AreEqual(RightsHelper.AllRights<InstanceManagerRights>(), group.PermissionSet.InstanceManagerRights);
|
||||
|
||||
UserUpdateRequest testUserUpdate = new UserCreateRequest
|
||||
{
|
||||
Name = "TestUserWithNoPassword",
|
||||
Password = string.Empty
|
||||
};
|
||||
|
||||
await ApiAssert.ThrowsException<ApiConflictException, UserResponse>(() => client.Users.Create((UserCreateRequest)testUserUpdate, cancellationToken), Api.Models.ErrorCode.UserPasswordLength);
|
||||
|
||||
testUserUpdate.OAuthConnections =
|
||||
[
|
||||
new()
|
||||
{
|
||||
ExternalUserId = "asdf",
|
||||
Provider = Api.Models.OAuthProvider.GitHub
|
||||
}
|
||||
];
|
||||
|
||||
var testUser2 = await client.Users.Create((UserCreateRequest)testUserUpdate, cancellationToken);
|
||||
|
||||
testUserUpdate = new UserUpdateRequest
|
||||
{
|
||||
Id = testUser2.Id,
|
||||
PermissionSet = testUser2.PermissionSet,
|
||||
Group = new Api.Models.Internal.UserGroup
|
||||
{
|
||||
Id = group.Id
|
||||
},
|
||||
};
|
||||
await ApiAssert.ThrowsException<ApiConflictException, UserResponse>(
|
||||
() => client.Users.Update(
|
||||
testUserUpdate,
|
||||
cancellationToken),
|
||||
Api.Models.ErrorCode.UserGroupAndPermissionSet);
|
||||
|
||||
testUserUpdate.PermissionSet = null;
|
||||
|
||||
testUser2 = await client.Users.Update(testUserUpdate, cancellationToken);
|
||||
|
||||
Assert.IsNull(testUser2.PermissionSet);
|
||||
Assert.IsNotNull(testUser2.Group);
|
||||
Assert.AreEqual(group.Id, testUser2.Group.Id);
|
||||
|
||||
var group4 = await client.Groups.GetId(group, cancellationToken);
|
||||
Assert.IsNotNull(group4.Users);
|
||||
Assert.AreEqual(1, group4.Users.Count);
|
||||
Assert.AreEqual(testUser2.Id, group4.Users.First().Id);
|
||||
Assert.IsNotNull(group4.PermissionSet);
|
||||
|
||||
testUserUpdate.Group = null;
|
||||
testUserUpdate.PermissionSet = new PermissionSet
|
||||
{
|
||||
AdministrationRights = RightsHelper.AllRights<AdministrationRights>(),
|
||||
InstanceManagerRights = RightsHelper.AllRights<InstanceManagerRights>(),
|
||||
};
|
||||
|
||||
testUser2 = await client.Users.Update(testUserUpdate, cancellationToken);
|
||||
Assert.IsNull(testUser2.Group);
|
||||
Assert.IsNotNull(testUser2.PermissionSet);
|
||||
},
|
||||
cancellationToken);
|
||||
|
||||
Assert.IsNotNull(testUser.OAuthConnections);
|
||||
testUser = await serverClient.Users.Update(
|
||||
new UserUpdateRequest
|
||||
{
|
||||
Id = testUser.Id,
|
||||
OAuthConnections = sampleOAuthConnections
|
||||
},
|
||||
cancellationToken);
|
||||
|
||||
Assert.AreEqual(1, testUser.OAuthConnections.Count);
|
||||
Assert.AreEqual(sampleOAuthConnections.First().ExternalUserId, testUser.OAuthConnections.First().ExternalUserId);
|
||||
Assert.AreEqual(sampleOAuthConnections.First().Provider, testUser.OAuthConnections.First().Provider);
|
||||
|
||||
|
||||
var group = await serverClient.Groups.Create(
|
||||
new UserGroupCreateRequest
|
||||
async client =>
|
||||
{
|
||||
Name = "TestGroup"
|
||||
},
|
||||
cancellationToken);
|
||||
Assert.AreEqual(group.Name, "TestGroup");
|
||||
Assert.IsNotNull(group.PermissionSet);
|
||||
Assert.IsNotNull(group.PermissionSet.Id);
|
||||
Assert.AreEqual(AdministrationRights.None, group.PermissionSet.AdministrationRights);
|
||||
Assert.AreEqual(InstanceManagerRights.None, group.PermissionSet.InstanceManagerRights);
|
||||
var result = await client.RunOperation(gql => gql.ListUsers.ExecuteAsync(cancellationToken), cancellationToken);
|
||||
result.EnsureNoErrors();
|
||||
var users = result.Data.Swarm.Users.QueryableUsers;
|
||||
Assert.IsTrue(users.TotalCount > 0);
|
||||
Assert.AreEqual(Math.Min(ApiController.DefaultPageSize, users.TotalCount), users.Nodes.Count);
|
||||
|
||||
var group2 = await serverClient.Groups.Create(new UserGroupCreateRequest
|
||||
{
|
||||
Name = "TestGroup2",
|
||||
PermissionSet = new PermissionSet
|
||||
{
|
||||
InstanceManagerRights = InstanceManagerRights.List
|
||||
}
|
||||
}, cancellationToken);
|
||||
Assert.AreEqual(AdministrationRights.None, group2.PermissionSet.AdministrationRights);
|
||||
Assert.AreEqual(InstanceManagerRights.List, group2.PermissionSet.InstanceManagerRights);
|
||||
var tgsUserResult = await client.RunOperation(gql => gql.GetUserNameByNodeId.ExecuteAsync(gqlUser.Swarm.Users.Current.CreatedBy.Id, cancellationToken), cancellationToken);
|
||||
tgsUserResult.EnsureNoErrors();
|
||||
var tgsUserResult2 = await client.RunOperation(gql => gql.GetUserById.ExecuteAsync(gqlUser.Swarm.Users.Current.CreatedBy.Id, cancellationToken), cancellationToken);
|
||||
Assert.IsTrue(tgsUserResult2.IsErrorResult());
|
||||
|
||||
var groups = await serverClient.Groups.List(null, cancellationToken);
|
||||
Assert.AreEqual(2, groups.Count);
|
||||
var sampleOAuthConnections = new List<OAuthConnectionInput>
|
||||
{
|
||||
new()
|
||||
{
|
||||
ExternalUserId = "asdfasdf",
|
||||
Provider = Client.GraphQL.OAuthProvider.Discord,
|
||||
}
|
||||
};
|
||||
|
||||
foreach (var igroup in groups)
|
||||
{
|
||||
Assert.IsNotNull(igroup.Users);
|
||||
Assert.IsNotNull(igroup.PermissionSet);
|
||||
}
|
||||
await ApiAssert.OperationFails(
|
||||
client,
|
||||
gql => gql.SetUserOAuthConnections.ExecuteAsync(
|
||||
gqlUser.Swarm.Users.Current.Id,
|
||||
sampleOAuthConnections,
|
||||
cancellationToken),
|
||||
data => data.UpdateUser,
|
||||
Client.GraphQL.ErrorCode.AdminUserCannotOAuth,
|
||||
cancellationToken);
|
||||
|
||||
await serverClient.Groups.Delete(group2, cancellationToken);
|
||||
var testUserResult = await client.RunMutationEnsureNoErrors(
|
||||
gql => gql.CreateUserWithPasswordSelectOAuthConnections.ExecuteAsync("BasicTestUser", "asdfasdjfhauwiehruiy273894234jhndjkwh", cancellationToken),
|
||||
data => data.CreateUserByPasswordAndPermissionSet,
|
||||
cancellationToken);
|
||||
|
||||
groups = await serverClient.Groups.List(null, cancellationToken);
|
||||
Assert.AreEqual(1, groups.Count);
|
||||
var testUserResult2 = await client.RunMutationEnsureNoErrors(
|
||||
gql => gql.UpdateUserOAuthConnections.ExecuteAsync(
|
||||
testUserResult.User.Id,
|
||||
sampleOAuthConnections,
|
||||
cancellationToken),
|
||||
data => data.UpdateUser,
|
||||
cancellationToken);
|
||||
|
||||
group = await serverClient.Groups.Update(new UserGroupUpdateRequest
|
||||
{
|
||||
Id = groups[0].Id,
|
||||
PermissionSet = new PermissionSet
|
||||
{
|
||||
InstanceManagerRights = RightsHelper.AllRights<InstanceManagerRights>(),
|
||||
AdministrationRights = RightsHelper.AllRights<AdministrationRights>(),
|
||||
}
|
||||
}, cancellationToken);
|
||||
var testUser = testUserResult2.User;
|
||||
Assert.IsNotNull(testUser.OAuthConnections);
|
||||
Assert.AreEqual(1, testUser.OAuthConnections.Count);
|
||||
Assert.AreEqual(sampleOAuthConnections.First().ExternalUserId, testUser.OAuthConnections[0].ExternalUserId);
|
||||
Assert.AreEqual(sampleOAuthConnections.First().Provider, testUser.OAuthConnections[0].Provider);
|
||||
|
||||
Assert.AreEqual(RightsHelper.AllRights<AdministrationRights>(), group.PermissionSet.AdministrationRights);
|
||||
Assert.AreEqual(RightsHelper.AllRights<InstanceManagerRights>(), group.PermissionSet.InstanceManagerRights);
|
||||
var groupResult = await client.RunMutationEnsureNoErrors(
|
||||
gql => gql.CreateUserGroup.ExecuteAsync("TestGroup", cancellationToken),
|
||||
data => data.CreateUserGroup,
|
||||
cancellationToken);
|
||||
|
||||
UserUpdateRequest testUserUpdate = new UserCreateRequest
|
||||
{
|
||||
Name = "TestUserWithNoPassword",
|
||||
Password = string.Empty
|
||||
};
|
||||
var group = groupResult.UserGroup;
|
||||
Assert.AreEqual(group.Name, "TestGroup");
|
||||
Assert.IsNotNull(group.PermissionSet);
|
||||
|
||||
await ApiAssert.ThrowsException<ApiConflictException, UserResponse>(() => serverClient.Users.Create((UserCreateRequest)testUserUpdate, cancellationToken), ErrorCode.UserPasswordLength);
|
||||
Assert.IsFalse(group.PermissionSet.InstanceManagerRights.CanSetOnline);
|
||||
Assert.IsFalse(group.PermissionSet.InstanceManagerRights.CanRelocate);
|
||||
Assert.IsFalse(group.PermissionSet.InstanceManagerRights.CanRename);
|
||||
Assert.IsFalse(group.PermissionSet.InstanceManagerRights.CanSetConfiguration);
|
||||
Assert.IsFalse(group.PermissionSet.InstanceManagerRights.CanRead);
|
||||
Assert.IsFalse(group.PermissionSet.InstanceManagerRights.CanCreate);
|
||||
Assert.IsFalse(group.PermissionSet.InstanceManagerRights.CanDelete);
|
||||
Assert.IsFalse(group.PermissionSet.InstanceManagerRights.CanGrantPermissions);
|
||||
Assert.IsFalse(group.PermissionSet.InstanceManagerRights.CanList);
|
||||
Assert.IsFalse(group.PermissionSet.InstanceManagerRights.CanSetAutoUpdate);
|
||||
Assert.IsFalse(group.PermissionSet.InstanceManagerRights.CanSetChatBotLimit);
|
||||
Assert.IsFalse(group.PermissionSet.InstanceManagerRights.CanSetConfiguration);
|
||||
|
||||
testUserUpdate.OAuthConnections = new List<OAuthConnection>
|
||||
{
|
||||
new OAuthConnection
|
||||
{
|
||||
ExternalUserId = "asdf",
|
||||
Provider = OAuthProvider.GitHub
|
||||
}
|
||||
};
|
||||
Assert.IsFalse(group.PermissionSet.AdministrationRights.CanChangeVersion);
|
||||
Assert.IsFalse(group.PermissionSet.AdministrationRights.CanDownloadLogs);
|
||||
Assert.IsFalse(group.PermissionSet.AdministrationRights.CanEditOwnOAuthConnections);
|
||||
Assert.IsFalse(group.PermissionSet.AdministrationRights.CanEditOwnPassword);
|
||||
Assert.IsFalse(group.PermissionSet.AdministrationRights.CanReadUsers);
|
||||
Assert.IsFalse(group.PermissionSet.AdministrationRights.CanRestartHost);
|
||||
Assert.IsFalse(group.PermissionSet.AdministrationRights.CanUploadVersion);
|
||||
Assert.IsFalse(group.PermissionSet.AdministrationRights.CanWriteUsers);
|
||||
|
||||
var testUser2 = await serverClient.Users.Create((UserCreateRequest)testUserUpdate, cancellationToken);
|
||||
var group2Result = await client.RunMutationEnsureNoErrors(
|
||||
gql => gql.CreateUserGroupWithInstanceListPerm.ExecuteAsync("TestGroup2", cancellationToken),
|
||||
data => data.CreateUserGroup,
|
||||
cancellationToken);
|
||||
|
||||
testUserUpdate = new UserUpdateRequest
|
||||
{
|
||||
Id = testUser2.Id,
|
||||
PermissionSet = testUser2.PermissionSet,
|
||||
Group = new Api.Models.Internal.UserGroup
|
||||
{
|
||||
Id = group.Id
|
||||
},
|
||||
};
|
||||
await ApiAssert.ThrowsException<ApiConflictException, UserResponse>(
|
||||
() => serverClient.Users.Update(
|
||||
testUserUpdate,
|
||||
cancellationToken),
|
||||
ErrorCode.UserGroupAndPermissionSet);
|
||||
var group2 = group2Result.UserGroup;
|
||||
|
||||
testUserUpdate.PermissionSet = null;
|
||||
Assert.IsFalse(group2.PermissionSet.InstanceManagerRights.CanSetOnline);
|
||||
Assert.IsFalse(group2.PermissionSet.InstanceManagerRights.CanRelocate);
|
||||
Assert.IsFalse(group2.PermissionSet.InstanceManagerRights.CanRename);
|
||||
Assert.IsFalse(group2.PermissionSet.InstanceManagerRights.CanSetConfiguration);
|
||||
Assert.IsFalse(group2.PermissionSet.InstanceManagerRights.CanRead);
|
||||
Assert.IsFalse(group2.PermissionSet.InstanceManagerRights.CanCreate);
|
||||
Assert.IsFalse(group2.PermissionSet.InstanceManagerRights.CanDelete);
|
||||
Assert.IsFalse(group2.PermissionSet.InstanceManagerRights.CanGrantPermissions);
|
||||
Assert.IsTrue(group2.PermissionSet.InstanceManagerRights.CanList);
|
||||
Assert.IsFalse(group2.PermissionSet.InstanceManagerRights.CanSetAutoUpdate);
|
||||
Assert.IsFalse(group2.PermissionSet.InstanceManagerRights.CanSetChatBotLimit);
|
||||
Assert.IsFalse(group2.PermissionSet.InstanceManagerRights.CanSetConfiguration);
|
||||
|
||||
testUser2 = await serverClient.Users.Update(testUserUpdate, cancellationToken);
|
||||
Assert.IsFalse(group2.PermissionSet.AdministrationRights.CanChangeVersion);
|
||||
Assert.IsFalse(group2.PermissionSet.AdministrationRights.CanDownloadLogs);
|
||||
Assert.IsFalse(group2.PermissionSet.AdministrationRights.CanEditOwnOAuthConnections);
|
||||
Assert.IsFalse(group2.PermissionSet.AdministrationRights.CanEditOwnPassword);
|
||||
Assert.IsFalse(group2.PermissionSet.AdministrationRights.CanReadUsers);
|
||||
Assert.IsFalse(group2.PermissionSet.AdministrationRights.CanRestartHost);
|
||||
Assert.IsFalse(group2.PermissionSet.AdministrationRights.CanUploadVersion);
|
||||
Assert.IsFalse(group2.PermissionSet.AdministrationRights.CanWriteUsers);
|
||||
|
||||
Assert.IsNull(testUser2.PermissionSet);
|
||||
Assert.IsNotNull(testUser2.Group);
|
||||
Assert.AreEqual(group.Id, testUser2.Group.Id);
|
||||
var groupsResult = await client.RunQueryEnsureNoErrors(
|
||||
gql => gql.ListUserGroups.ExecuteAsync(cancellationToken),
|
||||
cancellationToken);
|
||||
|
||||
group = await serverClient.Groups.GetId(group, cancellationToken);
|
||||
Assert.IsNotNull(group.Users);
|
||||
Assert.AreEqual(1, group.Users.Count);
|
||||
Assert.AreEqual(testUser2.Id, group.Users.First().Id);
|
||||
Assert.IsNotNull(group.PermissionSet);
|
||||
var groups = groupsResult.Swarm.Users.Groups.QueryableGroups;
|
||||
Assert.AreEqual(2, groups.TotalCount);
|
||||
|
||||
testUserUpdate.Group = null;
|
||||
testUserUpdate.PermissionSet = new PermissionSet
|
||||
{
|
||||
AdministrationRights = RightsHelper.AllRights<AdministrationRights>(),
|
||||
InstanceManagerRights = RightsHelper.AllRights<InstanceManagerRights>(),
|
||||
};
|
||||
foreach (var igroup in groups.Nodes)
|
||||
Assert.IsNotNull(igroup.Id);
|
||||
|
||||
testUser2 = await serverClient.Users.Update(testUserUpdate, cancellationToken);
|
||||
Assert.IsNull(testUser2.Group);
|
||||
Assert.IsNotNull(testUser2.PermissionSet);
|
||||
var deleteResult = await client.RunMutationEnsureNoErrors(
|
||||
gql => gql.DeleteUserGroup.ExecuteAsync(group2.Id, cancellationToken),
|
||||
data => data.DeleteEmptyUserGroup,
|
||||
cancellationToken);
|
||||
|
||||
groupsResult = await client.RunQueryEnsureNoErrors(
|
||||
gql => gql.ListUserGroups.ExecuteAsync(cancellationToken),
|
||||
cancellationToken);
|
||||
|
||||
groups = groupsResult.Swarm.Users.Groups.QueryableGroups;
|
||||
Assert.AreEqual(1, groups.TotalCount);
|
||||
|
||||
foreach (var igroup in groups.Nodes)
|
||||
Assert.IsNotNull(igroup.Id);
|
||||
|
||||
var group3Result = await client.RunMutationEnsureNoErrors(
|
||||
gql => gql.SetFullPermsOnUserGroup.ExecuteAsync(group.Id, cancellationToken),
|
||||
data => data.UpdateUserGroup,
|
||||
cancellationToken);
|
||||
|
||||
var group3 = group3Result.UserGroup;
|
||||
Assert.IsTrue(group3.PermissionSet.InstanceManagerRights.CanSetOnline);
|
||||
Assert.IsTrue(group3.PermissionSet.InstanceManagerRights.CanRelocate);
|
||||
Assert.IsTrue(group3.PermissionSet.InstanceManagerRights.CanRename);
|
||||
Assert.IsTrue(group3.PermissionSet.InstanceManagerRights.CanSetConfiguration);
|
||||
Assert.IsTrue(group3.PermissionSet.InstanceManagerRights.CanRead);
|
||||
Assert.IsTrue(group3.PermissionSet.InstanceManagerRights.CanCreate);
|
||||
Assert.IsTrue(group3.PermissionSet.InstanceManagerRights.CanDelete);
|
||||
Assert.IsTrue(group3.PermissionSet.InstanceManagerRights.CanGrantPermissions);
|
||||
Assert.IsTrue(group3.PermissionSet.InstanceManagerRights.CanList);
|
||||
Assert.IsTrue(group3.PermissionSet.InstanceManagerRights.CanSetAutoUpdate);
|
||||
Assert.IsTrue(group3.PermissionSet.InstanceManagerRights.CanSetChatBotLimit);
|
||||
Assert.IsTrue(group3.PermissionSet.InstanceManagerRights.CanSetConfiguration);
|
||||
|
||||
Assert.IsTrue(group3.PermissionSet.AdministrationRights.CanChangeVersion);
|
||||
Assert.IsTrue(group3.PermissionSet.AdministrationRights.CanDownloadLogs);
|
||||
Assert.IsTrue(group3.PermissionSet.AdministrationRights.CanEditOwnOAuthConnections);
|
||||
Assert.IsTrue(group3.PermissionSet.AdministrationRights.CanEditOwnPassword);
|
||||
Assert.IsTrue(group3.PermissionSet.AdministrationRights.CanReadUsers);
|
||||
Assert.IsTrue(group3.PermissionSet.AdministrationRights.CanRestartHost);
|
||||
Assert.IsTrue(group3.PermissionSet.AdministrationRights.CanUploadVersion);
|
||||
Assert.IsTrue(group3.PermissionSet.AdministrationRights.CanWriteUsers);
|
||||
|
||||
await ApiAssert.OperationFails(
|
||||
client,
|
||||
gql => gql.CreateUserWithPassword.ExecuteAsync("TestUserWithNoPassword", String.Empty, cancellationToken),
|
||||
data => data.CreateUserByPasswordAndPermissionSet,
|
||||
Client.GraphQL.ErrorCode.ModelValidationFailure,
|
||||
cancellationToken);
|
||||
|
||||
await ApiAssert.OperationFails(
|
||||
client,
|
||||
gql => gql.CreateUserWithPassword.ExecuteAsync("TestUserWithShortPassword", "a", cancellationToken),
|
||||
data => data.CreateUserByPasswordAndPermissionSet,
|
||||
Client.GraphQL.ErrorCode.UserPasswordLength,
|
||||
cancellationToken);
|
||||
|
||||
var oAuthCreateResult = await client.RunMutationEnsureNoErrors(
|
||||
gql => gql.CreateUserFromOAuthConnection.ExecuteAsync(
|
||||
"TestUserWithNoPassword",
|
||||
[
|
||||
new()
|
||||
{
|
||||
ExternalUserId = "asdf",
|
||||
Provider = Client.GraphQL.OAuthProvider.GitHub,
|
||||
}
|
||||
],
|
||||
cancellationToken),
|
||||
data => data.CreateUserByOAuthAndPermissionSet,
|
||||
cancellationToken);
|
||||
|
||||
var testUser2 = oAuthCreateResult.User;
|
||||
|
||||
var testUser22Result = await client.RunMutationEnsureNoErrors(
|
||||
gql => gql.SetUserGroup.ExecuteAsync(testUser2.Id, group.Id, cancellationToken),
|
||||
data => data.UpdateUserSetGroup,
|
||||
cancellationToken);
|
||||
|
||||
var testUser22 = testUser22Result.User;
|
||||
|
||||
Assert.IsNull(testUser22.OwnedPermissionSet);
|
||||
Assert.IsNotNull(testUser22.Group);
|
||||
Assert.AreEqual(group.Id, testUser22.Group.Id);
|
||||
|
||||
var group4Result = await client.RunQueryEnsureNoErrors(
|
||||
gql => gql.GetSomeGroupInfo.ExecuteAsync(group.Id, cancellationToken),
|
||||
cancellationToken);
|
||||
var group4 = group4Result.Swarm.Users.Groups.ById;
|
||||
|
||||
Assert.IsNotNull(group4.QueryableUsersByGroup.Nodes);
|
||||
Assert.AreEqual(1, group4.QueryableUsersByGroup.TotalCount);
|
||||
Assert.AreEqual(testUser2.Id, group4.QueryableUsersByGroup.Nodes[0].Id);
|
||||
Assert.IsNotNull(group4.PermissionSet);
|
||||
|
||||
var testUser4Result = await client.RunMutationEnsureNoErrors(
|
||||
gql => gql.SetUserPermissionSet.ExecuteAsync(
|
||||
testUser2.Id,
|
||||
new PermissionSetInput
|
||||
{
|
||||
AdministrationRights = new AdministrationRightsFlagsInput
|
||||
{
|
||||
CanChangeVersion = true,
|
||||
CanDownloadLogs = true,
|
||||
CanEditOwnOAuthConnections = true,
|
||||
CanEditOwnPassword = true,
|
||||
CanReadUsers = true,
|
||||
CanRestartHost = true,
|
||||
CanUploadVersion = true,
|
||||
CanWriteUsers = true,
|
||||
},
|
||||
InstanceManagerRights = new InstanceManagerRightsFlagsInput
|
||||
{
|
||||
CanCreate = true,
|
||||
CanDelete = true,
|
||||
CanGrantPermissions = true,
|
||||
CanList = true,
|
||||
CanRead = true,
|
||||
CanRelocate = true,
|
||||
CanRename = true,
|
||||
CanSetAutoUpdate = true,
|
||||
CanSetChatBotLimit = true,
|
||||
CanSetConfiguration = true,
|
||||
CanSetOnline = true,
|
||||
}
|
||||
},
|
||||
cancellationToken),
|
||||
data => data.UpdateUserSetOwnedPermissionSet,
|
||||
cancellationToken);
|
||||
|
||||
var testUser4 = testUser4Result.User;
|
||||
Assert.IsNull(testUser4.Group);
|
||||
Assert.IsNotNull(testUser4.OwnedPermissionSet);
|
||||
});
|
||||
}
|
||||
|
||||
async Task TestCreateSysUser(CancellationToken cancellationToken)
|
||||
ValueTask TestCreateSysUser(CancellationToken cancellationToken)
|
||||
{
|
||||
var sysId = Environment.UserName;
|
||||
var update = new UserCreateRequest
|
||||
{
|
||||
SystemIdentifier = sysId
|
||||
};
|
||||
if (new PlatformIdentifier().IsWindows)
|
||||
await serverClient.Users.Create(update, cancellationToken);
|
||||
else
|
||||
await ApiAssert.ThrowsException<MethodNotSupportedException, UserResponse>(() => serverClient.Users.Create(update, cancellationToken), ErrorCode.RequiresPosixSystemIdentity);
|
||||
|
||||
return serverClient.Execute(
|
||||
async restClient =>
|
||||
{
|
||||
var update = new UserCreateRequest
|
||||
{
|
||||
SystemIdentifier = sysId
|
||||
};
|
||||
if (new PlatformIdentifier().IsWindows)
|
||||
await restClient.Users.Create(update, cancellationToken);
|
||||
else
|
||||
await ApiAssert.ThrowsException<MethodNotSupportedException, UserResponse>(() => restClient.Users.Create(update, cancellationToken), Api.Models.ErrorCode.RequiresPosixSystemIdentity);
|
||||
},
|
||||
async graphQLClient =>
|
||||
{
|
||||
if (new PlatformIdentifier().IsWindows)
|
||||
{
|
||||
await graphQLClient.RunMutationEnsureNoErrors(
|
||||
gql => gql.CreateSystemUserWithPermissionSet.ExecuteAsync(sysId, cancellationToken),
|
||||
data => data.CreateUserBySystemIDAndPermissionSet,
|
||||
cancellationToken);
|
||||
}
|
||||
else
|
||||
await ApiAssert.OperationFails(
|
||||
graphQLClient,
|
||||
gql => gql.CreateSystemUserWithPermissionSet.ExecuteAsync(sysId, cancellationToken),
|
||||
data => data.CreateUserBySystemIDAndPermissionSet,
|
||||
Client.GraphQL.ErrorCode.RequiresPosixSystemIdentity,
|
||||
cancellationToken);
|
||||
});
|
||||
}
|
||||
|
||||
async Task TestSpamCreation(CancellationToken cancellationToken)
|
||||
async ValueTask TestSpamCreation(CancellationToken cancellationToken)
|
||||
{
|
||||
// Careful with this, very easy to overload the thread pool
|
||||
const int RepeatCount = 100;
|
||||
var tasks = new List<ValueTask<UserResponse>>(RepeatCount);
|
||||
var tasks = new List<ValueTask>(RepeatCount);
|
||||
|
||||
ThreadPool.GetMaxThreads(out var defaultMaxWorker, out var defaultMaxCompletion);
|
||||
ThreadPool.GetMinThreads(out var defaultMinWorker, out var defaultMinCompletion);
|
||||
ConcurrentBag<object> ids = new ConcurrentBag<object>();
|
||||
try
|
||||
{
|
||||
ThreadPool.SetMinThreads(Math.Min(RepeatCount * 4, defaultMaxWorker), Math.Min(RepeatCount * 4, defaultMaxCompletion));
|
||||
for (int i = 0; i < RepeatCount; ++i)
|
||||
{
|
||||
var task =
|
||||
serverClient.Users.Create(
|
||||
new UserCreateRequest
|
||||
var iLocal = i;
|
||||
ValueTask CreateSpamUser()
|
||||
=> serverClient.Execute(
|
||||
async restClient =>
|
||||
{
|
||||
Name = $"SpamTestUser_{i}",
|
||||
Password = "asdfasdjfhauwiehruiy273894234jhndjkwh"
|
||||
var user = await restClient.Users.Create(
|
||||
new UserCreateRequest
|
||||
{
|
||||
Name = $"SpamTestUser_{iLocal}",
|
||||
Password = "asdfasdjfhauwiehruiy273894234jhndjkwh"
|
||||
},
|
||||
cancellationToken);
|
||||
|
||||
ids.Add(user.Id);
|
||||
},
|
||||
cancellationToken);
|
||||
tasks.Add(task);
|
||||
async graphQLClient =>
|
||||
{
|
||||
var result = await graphQLClient.RunMutationEnsureNoErrors(
|
||||
gql => gql.CreateUserWithPassword.ExecuteAsync($"SpamTestUser_{iLocal}", "asdfasdjfhauwiehruiy273894234jhndjkwh", cancellationToken),
|
||||
data => data.CreateUserByPasswordAndPermissionSet,
|
||||
cancellationToken);
|
||||
|
||||
ids.Add(result.User.Id);
|
||||
});
|
||||
|
||||
tasks.Add(CreateSpamUser());
|
||||
}
|
||||
|
||||
await ValueTaskExtensions.WhenAll(tasks);
|
||||
@@ -251,57 +570,127 @@ namespace Tgstation.Server.Tests.Live
|
||||
ThreadPool.SetMinThreads(defaultMinWorker, defaultMinCompletion);
|
||||
}
|
||||
|
||||
Assert.AreEqual(RepeatCount, tasks.Select(task => task.Result.Id).Distinct().Count(), "Did not receive expected number of unique user IDs!");
|
||||
Assert.AreEqual(RepeatCount, ids.Distinct().Count(), "Did not receive expected number of unique user IDs!");
|
||||
}
|
||||
|
||||
async Task TestPagination(CancellationToken cancellationToken)
|
||||
ValueTask TestPagination(CancellationToken cancellationToken)
|
||||
{
|
||||
// we test pagination here b/c it's the only spot we have a decent amount of entities
|
||||
var nullSettings = await serverClient.Users.List(null, cancellationToken);
|
||||
var emptySettings = await serverClient.Users.List(
|
||||
new PaginationSettings
|
||||
const int ExpectedCount = 106;
|
||||
return serverClient.Execute(
|
||||
async restClient =>
|
||||
{
|
||||
}, cancellationToken);
|
||||
// we test pagination here b/c it's the only spot we have a decent amount of entities
|
||||
var nullSettings = await restClient.Users.List(null, cancellationToken);
|
||||
var emptySettings = await restClient.Users.List(
|
||||
new PaginationSettings
|
||||
{
|
||||
}, cancellationToken);
|
||||
|
||||
Assert.AreEqual(nullSettings.Count, emptySettings.Count);
|
||||
Assert.IsTrue(nullSettings.All(x => emptySettings.SingleOrDefault(y => x.Id == y.Id) != null));
|
||||
Assert.AreEqual(nullSettings.Count, emptySettings.Count);
|
||||
Assert.AreEqual(ExpectedCount, nullSettings.Count);
|
||||
Assert.IsTrue(nullSettings.All(x => emptySettings.SingleOrDefault(y => x.Id == y.Id) != null));
|
||||
|
||||
await ApiAssert.ThrowsException<ApiConflictException, List<UserResponse>>(() => serverClient.Users.List(
|
||||
new PaginationSettings
|
||||
{
|
||||
PageSize = -2143
|
||||
}, cancellationToken), ErrorCode.ApiInvalidPageOrPageSize);
|
||||
await ApiAssert.ThrowsException<ApiConflictException, List<UserResponse>>(() => serverClient.Users.List(
|
||||
new PaginationSettings
|
||||
{
|
||||
PageSize = int.MaxValue
|
||||
}, cancellationToken), ErrorCode.ApiPageTooLarge);
|
||||
await ApiAssert.ThrowsException<ApiConflictException, List<UserResponse>>(() => restClient.Users.List(
|
||||
new PaginationSettings
|
||||
{
|
||||
PageSize = -2143
|
||||
}, cancellationToken), Api.Models.ErrorCode.ApiInvalidPageOrPageSize);
|
||||
await ApiAssert.ThrowsException<ApiConflictException, List<UserResponse>>(() => restClient.Users.List(
|
||||
new PaginationSettings
|
||||
{
|
||||
PageSize = ApiController.MaximumPageSize + 1,
|
||||
}, cancellationToken), Api.Models.ErrorCode.ApiPageTooLarge);
|
||||
|
||||
await serverClient.Users.List(
|
||||
new PaginationSettings
|
||||
{
|
||||
PageSize = 50
|
||||
var users = await restClient.Users.List(
|
||||
new PaginationSettings
|
||||
{
|
||||
PageSize = ApiController.MaximumPageSize,
|
||||
RetrieveCount = ApiController.MaximumPageSize,
|
||||
},
|
||||
cancellationToken);
|
||||
|
||||
Assert.AreEqual(ApiController.MaximumPageSize, users.Count);
|
||||
|
||||
var skipped = await restClient.Users.List(new PaginationSettings
|
||||
{
|
||||
Offset = 50,
|
||||
RetrieveCount = 5
|
||||
}, cancellationToken);
|
||||
Assert.AreEqual(5, skipped.Count);
|
||||
|
||||
var allAfterSkipped = await restClient.Users.List(new PaginationSettings
|
||||
{
|
||||
Offset = 50,
|
||||
}, cancellationToken);
|
||||
Assert.IsTrue(5 < allAfterSkipped.Count);
|
||||
|
||||
var limited = await restClient.Users.List(new PaginationSettings
|
||||
{
|
||||
RetrieveCount = 12,
|
||||
}, cancellationToken);
|
||||
Assert.AreEqual(12, limited.Count);
|
||||
},
|
||||
cancellationToken);
|
||||
graphQLClient =>
|
||||
{
|
||||
async ValueTask TestPageSize(int? inputPageSize)
|
||||
{
|
||||
var outputPageSize = inputPageSize ?? ApiController.DefaultPageSize;
|
||||
|
||||
var skipped = await serverClient.Users.List(new PaginationSettings
|
||||
{
|
||||
Offset = 50,
|
||||
RetrieveCount = 5
|
||||
}, cancellationToken);
|
||||
Assert.AreEqual(5, skipped.Count);
|
||||
string cursor = null;
|
||||
|
||||
var allAfterSkipped = await serverClient.Users.List(new PaginationSettings
|
||||
{
|
||||
Offset = 50,
|
||||
}, cancellationToken);
|
||||
Assert.IsTrue(5 < allAfterSkipped.Count);
|
||||
var exactMatch = (ExpectedCount % outputPageSize) == 0;
|
||||
var expectedIterations = (ExpectedCount / outputPageSize) + (exactMatch ? 0 : 1);
|
||||
for (int i = 0; i < expectedIterations; ++i)
|
||||
{
|
||||
var isLastIteration = i == expectedIterations - 1;
|
||||
var queryable = (await graphQLClient.RunQueryEnsureNoErrors(
|
||||
gql => gql.PageUserIds.ExecuteAsync(inputPageSize, cursor, cancellationToken),
|
||||
cancellationToken))
|
||||
.Swarm
|
||||
.Users
|
||||
.QueryableUsers;
|
||||
|
||||
var limited = await serverClient.Users.List(new PaginationSettings
|
||||
{
|
||||
RetrieveCount = 12,
|
||||
}, cancellationToken);
|
||||
Assert.AreEqual(12, limited.Count);
|
||||
if (!isLastIteration || exactMatch)
|
||||
Assert.AreEqual(outputPageSize, queryable.Nodes.Count);
|
||||
else
|
||||
Assert.AreEqual(ExpectedCount % outputPageSize, queryable.Nodes.Count);
|
||||
Assert.AreEqual(!isLastIteration, queryable.PageInfo.HasNextPage);
|
||||
Assert.IsNotNull(queryable.PageInfo.EndCursor);
|
||||
|
||||
cursor = queryable.PageInfo.EndCursor;
|
||||
}
|
||||
}
|
||||
|
||||
async ValueTask TestBadPageSize(int size)
|
||||
{
|
||||
var result = await graphQLClient.RunOperation(
|
||||
gql => gql.PageUserIds.ExecuteAsync(size, null, cancellationToken),
|
||||
cancellationToken);
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
// special case
|
||||
result.EnsureNoErrors();
|
||||
Assert.AreEqual(0, result.Data.Swarm.Users.QueryableUsers.Nodes.Count);
|
||||
return;
|
||||
}
|
||||
|
||||
var errored = result.IsErrorResult();
|
||||
Assert.IsTrue(errored);
|
||||
}
|
||||
|
||||
return ValueTaskExtensions.WhenAll(
|
||||
TestPageSize(null),
|
||||
TestPageSize(ApiController.DefaultPageSize),
|
||||
TestPageSize(ApiController.DefaultPageSize / 2),
|
||||
TestPageSize(ApiController.MaximumPageSize),
|
||||
TestPageSize(1),
|
||||
TestBadPageSize(-1),
|
||||
TestBadPageSize(0),
|
||||
TestBadPageSize(ApiController.MaximumPageSize + 1),
|
||||
TestBadPageSize(Int32.MinValue),
|
||||
TestBadPageSize(Int32.MaxValue));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user