From 300d01bf7f146c2d7444af381fa74b1a0b724eb4 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Tue, 3 Nov 2020 00:53:21 +0100 Subject: [PATCH] Reworked Stitching Error Handling (#2529) --- .../Data/src/Data/Filters/FilterInputType.cs | 1 + .../Stitching/HotChocolate.Stitching.sln | 28 +- .../Stitching.Redis/SchemaDefinitionDto.cs | 3 +- .../DelegateToRemoteSchemaMiddleware.cs | 102 +++-- .../Stitching/Pipeline/HttpRequestClient.cs | 20 +- .../Pipeline/HttpResponseDeserializer.cs | 83 ++++- .../Stitching/Requests/MergeRequestHelper.cs | 10 +- .../Client/RemoteQueryClientTests.txt | 350 ------------------ .../Client/StitchingContextTests.txt | 109 ------ ...atchMultipleQueriesAndRewriteErrors_A.snap | 8 - ...atchMultipleQueriesAndRewriteErrors_B.snap | 20 - ...riesDistinctOperationName_MergedQuery.snap | 1 - ...QueriesDistinctOperationName_Result_A.snap | 8 - ...QueriesDistinctOperationName_Result_B.snap | 9 - ...patchMultipleQueriesWithGlobalError_A.snap | 8 - ...patchMultipleQueriesWithGlobalError_B.snap | 18 - .../DispatchMultipleQueries_MergedQuery.snap | 1 - .../DispatchMultipleQueries_Result_A.snap | 8 - .../DispatchMultipleQueries_Result_B.snap | 9 - ....DispatchMultipleQueriesWithVariables.snap | 15 - ...eQueryClientTests.DispatchSingleQuery.snap | 1 - ..._Variable_Is_Converted_To_Int_Literal.snap | 8 - ...riable_Is_Converted_To_String_Literal.snap | 10 - .../Integration/FederatedRedisSchemaTests.cs | 2 +- .../Integration/FederatedSchemaErrorTests.cs | 250 +++++++++++++ .../Integration/FederatedSchemaTests.cs | 2 +- .../__snapshots__/BaseTests.Foo.snap | 27 -- ...atedSchemaErrorTests.AutoMerge_Schema.snap | 71 ++++ ...rror_StatusCode_On_DownStream_Request.snap | 13 + .../Schemas/Products/ProductRepository.cs | 1 + .../ExtractFieldQuerySyntaxRewriterTests.txt | 193 ---------- .../FieldDependencyResolverTests.txt | 49 --- .../Utilities/HttpQueryClientTests.txt | 104 ------ .../HttpResponseDeserializerTests.txt | 189 ---------- .../Utilities/MergeQueryRewriterTests.txt | 176 --------- .../__snapshots__/AliasesMapIsCorrect_A.snap | 3 - .../__snapshots__/AliasesMapIsCorrect_B.snap | 3 - .../DeserializeQueryResult_bool.snap | 22 -- .../DeserializeQueryResult_flot.snap | 22 -- .../DeserializeQueryResult_int.snap | 22 -- .../DeserializeQueryResult_string.snap | 22 -- ...raphql_StitchingQueryWithSkip.graphql.snap | 11 - ...tching.graphql_StitchingQuery.graphql.snap | 11 - ...l_StitchingQueryWithArguments.graphql.snap | 6 - ...titchingQueryWithFragmentDefs.graphql.snap | 11 - ...tchingQueryWithInlineFragment.graphql.snap | 11 - ...ql_StitchingQueryWithTypename.graphql.snap | 6 - ...aphql_StitchingQueryWithUnion.graphql.snap | 26 -- ...l_StitchingQueryWithVariables.graphql.snap | 12 - ...l_StitchingQueryComputedField.graphql.snap | 7 - ...ests.ExtractField_WithCustomRewriters.snap | 13 - ...ncyResolverTests.GetFieldDependencies.snap | 6 - ...ests.DeserializeQueryResultOnlyErrors.snap | 43 --- ...ests.DeserializeQueryResultWithErrors.snap | 59 --- ....DeserializeQueryResultWithExtensions.snap | 38 -- ...eQueryResultWithExtensions_extensions.snap | 26 -- ...ewriterTests.QueryWithGlobalVariables.snap | 32 -- ...writerTests.QueryWithPrivateVariables.snap | 46 --- ...eryRewriterTests.SimpleShortHandQuery.snap | 11 - 59 files changed, 514 insertions(+), 1862 deletions(-) delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Client/RemoteQueryClientTests.txt delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Client/StitchingContextTests.txt delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueriesAndRewriteErrors_A.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueriesAndRewriteErrors_B.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueriesDistinctOperationName_MergedQuery.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueriesDistinctOperationName_Result_A.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueriesDistinctOperationName_Result_B.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueriesWithGlobalError_A.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueriesWithGlobalError_B.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueries_MergedQuery.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueries_Result_A.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueries_Result_B.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/RemoteQueryClientTests.DispatchMultipleQueriesWithVariables.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/RemoteQueryClientTests.DispatchSingleQuery.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/StitchingContextTests.Int_Variable_Is_Converted_To_Int_Literal.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/StitchingContextTests.String_Variable_Is_Converted_To_String_Literal.snap create mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Integration/FederatedSchemaErrorTests.cs delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Integration/__snapshots__/BaseTests.Foo.snap create mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Integration/__snapshots__/FederatedSchemaErrorTests.AutoMerge_Schema.snap create mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Integration/__snapshots__/FederatedSchemaErrorTests.Execute_Error_StatusCode_On_DownStream_Request.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/ExtractFieldQuerySyntaxRewriterTests.txt delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/FieldDependencyResolverTests.txt delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/HttpQueryClientTests.txt delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/HttpResponseDeserializerTests.txt delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/MergeQueryRewriterTests.txt delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/AliasesMapIsCorrect_A.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/AliasesMapIsCorrect_B.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/DeserializeQueryResult_bool.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/DeserializeQueryResult_flot.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/DeserializeQueryResult_int.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/DeserializeQueryResult_string.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractFieldWithDirective_Stitching.graphql_StitchingQueryWithSkip.graphql.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_Stitching.graphql_StitchingQuery.graphql.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_Stitching.graphql_StitchingQueryWithArguments.graphql.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_Stitching.graphql_StitchingQueryWithFragmentDefs.graphql.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_Stitching.graphql_StitchingQueryWithInlineFragment.graphql.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_Stitching.graphql_StitchingQueryWithTypename.graphql.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_Stitching.graphql_StitchingQueryWithUnion.graphql.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_Stitching.graphql_StitchingQueryWithVariables.graphql.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_StitchingComputed.graphql_StitchingQueryComputedField.graphql.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_WithCustomRewriters.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/FieldDependencyResolverTests.GetFieldDependencies.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/HttpResponseDeserializerTests.DeserializeQueryResultOnlyErrors.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/HttpResponseDeserializerTests.DeserializeQueryResultWithErrors.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/HttpResponseDeserializerTests.DeserializeQueryResultWithExtensions.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/HttpResponseDeserializerTests.DeserializeQueryResultWithExtensions_extensions.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/MergeQueryRewriterTests.QueryWithGlobalVariables.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/MergeQueryRewriterTests.QueryWithPrivateVariables.snap delete mode 100644 src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/MergeQueryRewriterTests.SimpleShortHandQuery.snap diff --git a/src/HotChocolate/Data/src/Data/Filters/FilterInputType.cs b/src/HotChocolate/Data/src/Data/Filters/FilterInputType.cs index 24b75e69104..b031690df5e 100644 --- a/src/HotChocolate/Data/src/Data/Filters/FilterInputType.cs +++ b/src/HotChocolate/Data/src/Data/Filters/FilterInputType.cs @@ -66,6 +66,7 @@ protected virtual void Configure(IFilterInputTypeDescriptor descriptor) { fields.Add(new AndField(context.DescriptorContext, def.Scope)); } + if (definition is FilterInputTypeDefinition { UseOr: true } defOr) { fields.Add(new OrField(context.DescriptorContext, defOr.Scope)); diff --git a/src/HotChocolate/Stitching/HotChocolate.Stitching.sln b/src/HotChocolate/Stitching/HotChocolate.Stitching.sln index 4ef9543855a..cadb49532de 100644 --- a/src/HotChocolate/Stitching/HotChocolate.Stitching.sln +++ b/src/HotChocolate/Stitching/HotChocolate.Stitching.sln @@ -47,7 +47,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HotChocolate.AspNetCore.Tes EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HotChocolate.Stitching.Abstractions", "src\Stitching.Abstractions\HotChocolate.Stitching.Abstractions.csproj", "{E25716BB-CAD4-4FAA-BFFB-9D1F56E3B6AB}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stitching.Redis", "src\Stitching.Redis\Stitching.Redis.csproj", "{5492C256-DD42-45DC-8515-F1281F30E99E}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HotChocolate.Stitching.Redis", "src\Stitching.Redis\HotChocolate.Stitching.Redis.csproj", "{46B6437B-5AC2-41E6-89C6-CC0FE42190A1}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -251,18 +251,18 @@ Global {E25716BB-CAD4-4FAA-BFFB-9D1F56E3B6AB}.Release|x64.Build.0 = Release|Any CPU {E25716BB-CAD4-4FAA-BFFB-9D1F56E3B6AB}.Release|x86.ActiveCfg = Release|Any CPU {E25716BB-CAD4-4FAA-BFFB-9D1F56E3B6AB}.Release|x86.Build.0 = Release|Any CPU - {5492C256-DD42-45DC-8515-F1281F30E99E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5492C256-DD42-45DC-8515-F1281F30E99E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5492C256-DD42-45DC-8515-F1281F30E99E}.Debug|x64.ActiveCfg = Debug|Any CPU - {5492C256-DD42-45DC-8515-F1281F30E99E}.Debug|x64.Build.0 = Debug|Any CPU - {5492C256-DD42-45DC-8515-F1281F30E99E}.Debug|x86.ActiveCfg = Debug|Any CPU - {5492C256-DD42-45DC-8515-F1281F30E99E}.Debug|x86.Build.0 = Debug|Any CPU - {5492C256-DD42-45DC-8515-F1281F30E99E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5492C256-DD42-45DC-8515-F1281F30E99E}.Release|Any CPU.Build.0 = Release|Any CPU - {5492C256-DD42-45DC-8515-F1281F30E99E}.Release|x64.ActiveCfg = Release|Any CPU - {5492C256-DD42-45DC-8515-F1281F30E99E}.Release|x64.Build.0 = Release|Any CPU - {5492C256-DD42-45DC-8515-F1281F30E99E}.Release|x86.ActiveCfg = Release|Any CPU - {5492C256-DD42-45DC-8515-F1281F30E99E}.Release|x86.Build.0 = Release|Any CPU + {46B6437B-5AC2-41E6-89C6-CC0FE42190A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {46B6437B-5AC2-41E6-89C6-CC0FE42190A1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {46B6437B-5AC2-41E6-89C6-CC0FE42190A1}.Debug|x64.ActiveCfg = Debug|Any CPU + {46B6437B-5AC2-41E6-89C6-CC0FE42190A1}.Debug|x64.Build.0 = Debug|Any CPU + {46B6437B-5AC2-41E6-89C6-CC0FE42190A1}.Debug|x86.ActiveCfg = Debug|Any CPU + {46B6437B-5AC2-41E6-89C6-CC0FE42190A1}.Debug|x86.Build.0 = Debug|Any CPU + {46B6437B-5AC2-41E6-89C6-CC0FE42190A1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {46B6437B-5AC2-41E6-89C6-CC0FE42190A1}.Release|Any CPU.Build.0 = Release|Any CPU + {46B6437B-5AC2-41E6-89C6-CC0FE42190A1}.Release|x64.ActiveCfg = Release|Any CPU + {46B6437B-5AC2-41E6-89C6-CC0FE42190A1}.Release|x64.Build.0 = Release|Any CPU + {46B6437B-5AC2-41E6-89C6-CC0FE42190A1}.Release|x86.ActiveCfg = Release|Any CPU + {46B6437B-5AC2-41E6-89C6-CC0FE42190A1}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -284,7 +284,7 @@ Global {C1CF3B06-4A02-46A6-98B2-448B5DD4E7D3} = {D7A7C1D4-6239-4B4C-A80C-E953334A83F8} {709EE9F8-BA48-4C5A-8BDA-96B96689A1FC} = {D7A7C1D4-6239-4B4C-A80C-E953334A83F8} {E25716BB-CAD4-4FAA-BFFB-9D1F56E3B6AB} = {D530CEBF-33A3-4BCE-9887-A50F5AE789A3} - {5492C256-DD42-45DC-8515-F1281F30E99E} = {D530CEBF-33A3-4BCE-9887-A50F5AE789A3} + {46B6437B-5AC2-41E6-89C6-CC0FE42190A1} = {D530CEBF-33A3-4BCE-9887-A50F5AE789A3} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {FB1557E1-2F94-4540-93E5-B47698838B72} diff --git a/src/HotChocolate/Stitching/src/Stitching.Redis/SchemaDefinitionDto.cs b/src/HotChocolate/Stitching/src/Stitching.Redis/SchemaDefinitionDto.cs index 4e056dba590..d053bcf0c06 100644 --- a/src/HotChocolate/Stitching/src/Stitching.Redis/SchemaDefinitionDto.cs +++ b/src/HotChocolate/Stitching/src/Stitching.Redis/SchemaDefinitionDto.cs @@ -1,11 +1,10 @@ using System.Collections.Generic; -using HotChocolate.Execution.Options; namespace HotChocolate.Stitching.Redis { internal sealed class SchemaDefinitionDto { - public string Name { get; set; } + public string? Name { get; set; } public string? Document { get; set; } diff --git a/src/HotChocolate/Stitching/src/Stitching/Delegation/DelegateToRemoteSchemaMiddleware.cs b/src/HotChocolate/Stitching/src/Stitching/Delegation/DelegateToRemoteSchemaMiddleware.cs index c74f6242290..e39681e15f2 100644 --- a/src/HotChocolate/Stitching/src/Stitching/Delegation/DelegateToRemoteSchemaMiddleware.cs +++ b/src/HotChocolate/Stitching/src/Stitching/Delegation/DelegateToRemoteSchemaMiddleware.cs @@ -1,4 +1,5 @@ using System; +using System.Buffers; using System.Collections; using System.Collections.Generic; using System.Collections.Immutable; @@ -67,7 +68,7 @@ public async Task InvokeAsync(IMiddlewareContext context) context.Result = value is null or NullValueNode ? null : new SerializedData(value); if (result.Errors is not null) { - ReportErrors(delegateDirective.Schema, context, result.Errors); + ReportErrors(delegateDirective.Schema, context, path, result.Errors); } } @@ -224,24 +225,27 @@ public async Task InvokeAsync(IMiddlewareContext context) private static void ReportErrors( NameString schemaName, IResolverContext context, + IImmutableStack fetchPath, IEnumerable errors) { foreach (IError error in errors) { - IErrorBuilder builder = ErrorBuilder.FromError(error) + IErrorBuilder builder = ErrorBuilder + .FromError(error) .SetExtension(_remoteErrorField, error.RemoveException()) .SetExtension(_schemaNameErrorField, schemaName.Value); - if (error.Path != null) + if (error.Path is not null) { - Path path = RewriteErrorPath(error, context.Path); - builder.SetPath(path) + builder + .SetPath(RewriteErrorPath(error.Path, context.Path, fetchPath)) .ClearLocations() .AddLocation(context.FieldSelection); } else if (IsHttpError(error)) { - builder.SetPath(context.Path) + builder + .SetPath(context.Path) .ClearLocations() .AddLocation(context.FieldSelection); } @@ -250,40 +254,66 @@ public async Task InvokeAsync(IMiddlewareContext context) } } - private static Path RewriteErrorPath(IError error, Path path) + private static Path RewriteErrorPath( + Path errorPath, + Path fieldPath, + IImmutableStack fetchPath) { - // TODO : FIX THIS - Path current = path; - - /* - if (error.Path.Depth > 0 && - error.Path is NamePathSegment p1 && - path is NamePathSegment p2 && - p1.Name.Equals(p2.Name)) - { - while() - } + var depth = errorPath.Depth + 1; + Path[] buffer = ArrayPool.Shared.Rent(depth); + Span paths = buffer.AsSpan().Slice(0, depth); - if (error.Path.Depth > 0 - && error.Path[0] is string s - && current.Name.Equals(s)) + try { - for (int i = 1; i < error.Path.Count; i++) + Path? current = errorPath; + + do { - if (error.Path[i] is string name) + paths[--depth] = current; + current = current.Parent; + } while (current is not null && current is not RootPathSegment); + + depth = 0; + while (!fetchPath.IsEmpty) + { + fetchPath = fetchPath.Pop(out SelectionPathComponent fp); + if (paths[depth] is NamePathSegment np && np.Name.Equals(fp.Name.Value)) { - current = current.Append(name); + depth++; } + else + { + return fieldPath; + } + } + + paths = depth == 0 ? paths.Slice(1) : paths.Slice(depth); + + if (paths.Length == 0) + { + return fieldPath; + } - if (error.Path[i] is int index) + current = fieldPath; + + for (int i = 0; i < paths.Length; i++) + { + if (paths[i] is IndexerPathSegment index) + { + current = current.Append(index.Index); + } + else if (paths[i] is NamePathSegment name) { - current = current.Append(index); + current = current.Append(name.Name); } } - } - */ - return current; + return current; + } + finally + { + ArrayPool.Shared.Return(buffer); + } } private static bool IsHttpError(IError error) => @@ -370,13 +400,13 @@ private static Path RewriteErrorPath(IError error, Path path) return field; } - private static void ResolveScopedVariableArguments( - IResolverContext context, - NameString schemaName, - SelectionPathComponent component, - IOutputField field, - ICollection variables, - ExtractFieldQuerySyntaxRewriter rewriter) + private static void ResolveScopedVariableArguments( + IResolverContext context, + NameString schemaName, + SelectionPathComponent component, + IOutputField field, + ICollection variables, + ExtractFieldQuerySyntaxRewriter rewriter) { foreach (ArgumentNode argument in component.Arguments) { diff --git a/src/HotChocolate/Stitching/src/Stitching/Pipeline/HttpRequestClient.cs b/src/HotChocolate/Stitching/src/Stitching/Pipeline/HttpRequestClient.cs index cda4fedc46f..a83990cfa22 100644 --- a/src/HotChocolate/Stitching/src/Stitching/Pipeline/HttpRequestClient.cs +++ b/src/HotChocolate/Stitching/src/Stitching/Pipeline/HttpRequestClient.cs @@ -48,7 +48,7 @@ internal class HttpRequestClient { using var writer = new ArrayWriter(); - HttpRequestMessage requestMessage = + using HttpRequestMessage requestMessage = await CreateRequestAsync(writer, request, targetSchema, cancellationToken) .ConfigureAwait(false); @@ -89,7 +89,7 @@ await CreateRequestAsync(writer, request, targetSchema, cancellationToken) cancellationToken) .ConfigureAwait(false); } - catch(Exception ex) + catch (Exception ex) { IError error = _errorHandler.CreateUnexpectedError(ex) .SetCode(ErrorCodes.Stitching.UnknownRequestException) @@ -97,10 +97,6 @@ await CreateRequestAsync(writer, request, targetSchema, cancellationToken) return QueryResultBuilder.CreateError(error); } - finally - { - requestMessage.Dispose(); - } } internal static async ValueTask CreateRequestMessageAsync( @@ -141,8 +137,14 @@ await CreateRequestAsync(writer, request, targetSchema, cancellationToken) try { - return await ParseResponseMessageAsync(responseMessage, cancellationToken) - .ConfigureAwait(false); + IReadOnlyDictionary response = + await BufferHelper.ReadAsync( + stream, + ParseResponse, + cancellationToken) + .ConfigureAwait(false); + + return HttpResponseDeserializer.Deserialize(response); } catch { @@ -231,7 +233,7 @@ await _requestInterceptor Utf8JsonWriter jsonWriter, IReadOnlyDictionary? variables) { - if (variables is not null && variables.Count > 0) + if (variables is not null && variables.Count > 0) { jsonWriter.WritePropertyName("variables"); diff --git a/src/HotChocolate/Stitching/src/Stitching/Pipeline/HttpResponseDeserializer.cs b/src/HotChocolate/Stitching/src/Stitching/Pipeline/HttpResponseDeserializer.cs index adfc0e8aedf..5b1b02df64b 100644 --- a/src/HotChocolate/Stitching/src/Stitching/Pipeline/HttpResponseDeserializer.cs +++ b/src/HotChocolate/Stitching/src/Stitching/Pipeline/HttpResponseDeserializer.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using HotChocolate.Execution; @@ -40,14 +41,88 @@ internal static class HttpResponseDeserializer IReadOnlyDictionary serializedResult) { if (serializedResult.TryGetValue(_errors, out object? o) - && o is ListValueNode l) + && o is IReadOnlyList errors) { - foreach (var error in l.Items.OfType()) + foreach (var obj in errors) { - Dictionary dict = _converter.Convert(error); - result.AddError(ErrorBuilder.FromDictionary(dict).Build()); + IError error = ErrorBuilder + .FromDictionary(DeserializeErrorObject(obj)) + .Build(); + + result.AddError(error); } } } + + private static object? DeserializeErrorValue(object? value) + { + switch (value) + { + case IReadOnlyDictionary obj: + return DeserializeErrorObject(obj); + + case IReadOnlyList list: + return DeserializeErrorList(list); + + case StringValueNode sv: + return sv.Value; + + case EnumValueNode ev: + return ev.Value; + + case IntValueNode iv: + return iv.ToInt32(); + + case FloatValueNode fv: + return fv.ToDouble(); + + case BooleanValueNode bv: + return bv.Value; + + case NullValueNode: + case null: + return null; + + default: + throw new NotSupportedException(); + } + } + + private static Dictionary DeserializeErrorObject( + object obj) + { + if (obj is IReadOnlyDictionary dict) + { + return DeserializeErrorObject(dict); + } + + throw new NotSupportedException("An error object must be a dictionary."); + } + + private static Dictionary DeserializeErrorObject( + IReadOnlyDictionary obj) + { + var deserialized = new Dictionary(); + + foreach (var item in obj) + { + deserialized.Add(item.Key, DeserializeErrorValue(item.Value)); + } + + return deserialized; + } + + private static List DeserializeErrorList( + IReadOnlyList list) + { + var deserialized = new List(); + + foreach (var item in list) + { + deserialized.Add(DeserializeErrorValue(item)); + } + + return deserialized; + } } } diff --git a/src/HotChocolate/Stitching/src/Stitching/Requests/MergeRequestHelper.cs b/src/HotChocolate/Stitching/src/Stitching/Requests/MergeRequestHelper.cs index 1ba3ecb70b4..b2ba4018b6a 100644 --- a/src/HotChocolate/Stitching/src/Stitching/Requests/MergeRequestHelper.cs +++ b/src/HotChocolate/Stitching/src/Stitching/Requests/MergeRequestHelper.cs @@ -230,17 +230,17 @@ private static IError RewriteError(IError error, string responseName) private static Path ReplaceRoot(Path path, string responseName) { - Path[] buffer = ArrayPool.Shared.Rent(path.Depth); - Span paths = buffer.AsSpan().Slice(0, path.Depth); + var depth = path.Depth + 1; + Path[] buffer = ArrayPool.Shared.Rent(depth); + Span paths = buffer.AsSpan().Slice(0, depth); try { - var i = path.Depth; Path? current = path; do { - paths[--i] = current; + paths[--depth] = current; current = current.Parent; } while (current is not null && current is not RootPathSegment); @@ -248,7 +248,7 @@ private static Path ReplaceRoot(Path path, string responseName) current = Path.New(responseName); - for (i = 0; i < paths.Length; i++) + for (int i = 0; i < paths.Length; i++) { if (paths[i] is IndexerPathSegment index) { diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/RemoteQueryClientTests.txt b/src/HotChocolate/Stitching/test/Stitching.Tests/Client/RemoteQueryClientTests.txt deleted file mode 100644 index efc23b0427f..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/RemoteQueryClientTests.txt +++ /dev/null @@ -1,350 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using HotChocolate.Execution; -using HotChocolate.Stitching.Client; -using HotChocolate.Stitching.Requests; -using HotChocolate.Utilities; -using Moq; -using Snapshooter.Xunit; -using Xunit; - -namespace HotChocolate.Stitching -{ - public class RemoteQueryClientTests - { - [Fact] - public async Task DispatchSingleQuery() - { - // arrange - string query = null; - - var executor = new Mock(); - executor.Setup(t => t.ExecuteAsync( - It.IsAny(), - It.IsAny())) - .Returns(new Func>((r, ct) => - { - query = r.Query.ToString(); - return Task.FromResult(null); - })); - - var client = new RemoteRequestExecutor( - new EmptyServiceProvider(), - executor.Object); - - // act - Task result = client.ExecuteAsync( - QueryRequestBuilder.New() - .SetQuery("{ a }") - .Create()); - await client.DispatchAsync(CancellationToken.None); - await result; - - - query.MatchSnapshot(); - } - - [Fact] - public async Task DispatchMultipleQueries() - { - // arrange - string query = null; - int count = 0; - - var result = QueryResultBuilder.New(); - var data = new OrderedDictionary(); - data["__0__a"] = "a"; - data["__1__a"] = "b"; - data["__1__b"] = "c"; - result.SetData(data); - - var executor = new Mock(); - executor.Setup(t => t.ExecuteAsync( - It.IsAny(), - It.IsAny())) - .Returns(new Func>((r, ct) => - { - count++; - query = r.Query.ToString(); - return Task.FromResult(result.Create()); - })); - - var request_a = QueryRequestBuilder.Create("query a { a }"); - var request_b = QueryRequestBuilder.Create("query b { a b }"); - - var client = new RemoteRequestExecutor( - new EmptyServiceProvider(), - executor.Object); - - // act - Task task_a = client.ExecuteAsync(request_a); - Task task_b = client.ExecuteAsync(request_b); - await client.DispatchAsync(CancellationToken.None); - - // assert - Assert.Equal(1, count); - query.MatchSnapshot($"{nameof(DispatchMultipleQueries)}_MergedQuery"); - - IExecutionResult result_a = await task_a; - result_a.MatchSnapshot($"{nameof(DispatchMultipleQueries)}_Result_A"); - - IExecutionResult result_b = await task_b; - result_b.MatchSnapshot($"{nameof(DispatchMultipleQueries)}_Result_B"); - } - - [Fact] - public async Task DispatchMultipleQueriesDistinctOperationName() - { - // arrange - string query = null; - int count = 0; - - var result = QueryResultBuilder.New(); - var data = new OrderedDictionary(); - data["__0__a"] = "a"; - data["__1__a"] = "b"; - data["__1__b"] = "c"; - result.SetData(data); - - var executor = new Mock(); - executor.Setup(t => t.ExecuteAsync( - It.IsAny(), - It.IsAny())) - .Returns(new Func>((r, ct) => - { - count++; - query = r.Query.ToString(); - return Task.FromResult(result.Create()); - })); - - var request_a = QueryRequestBuilder.New().SetQuery("query a { a }").SetOperation("a").Create(); - var request_b = QueryRequestBuilder.New().SetQuery("query b { a b }").SetOperation("a").Create(); - - var client = new RemoteRequestExecutor( - new EmptyServiceProvider(), - executor.Object); - - // act - Task task_a = client.ExecuteAsync(request_a); - Task task_b = client.ExecuteAsync(request_b); - await client.DispatchAsync(CancellationToken.None); - - // assert - Assert.Equal(1, count); - query.MatchSnapshot($"{nameof(DispatchMultipleQueriesDistinctOperationName)}_MergedQuery"); - - IExecutionResult result_a = await task_a; - result_a.MatchSnapshot($"{nameof(DispatchMultipleQueriesDistinctOperationName)}_Result_A"); - - IExecutionResult result_b = await task_b; - result_b.MatchSnapshot($"{nameof(DispatchMultipleQueriesDistinctOperationName)}_Result_B"); - } - - [Fact] - public async Task DispatchMultipleQueriesAndRewriteErrors() - { - // arrange - string query = null; - int count = 0; - - var result = QueryResultBuilder.New(); - var data = new OrderedDictionary(); - data["__0__a"] = "a"; - data["__1__a"] = "b"; - data["__1__b"] = "c"; - result.SetData(data); - result.AddError(ErrorBuilder.New() - .SetMessage("foo") - .SetPath(Path.New("__1__b")) - .Build()); - - var executor = new Mock(); - executor.Setup(t => t.ExecuteAsync( - It.IsAny(), - It.IsAny())) - .Returns(new Func>((r, ct) => - { - count++; - query = r.Query.ToString(); - return Task.FromResult(result.Create()); - })); - - var request_a = QueryRequestBuilder.Create("query a { a }"); - var request_b = QueryRequestBuilder.Create("query b { a b }"); - - var client = new RemoteRequestExecutor( - new EmptyServiceProvider(), - executor.Object); - - // act - Task task_a = client.ExecuteAsync(request_a); - Task task_b = client.ExecuteAsync(request_b); - await client.DispatchAsync(CancellationToken.None); - - // assert - Assert.Equal(1, count); - - IExecutionResult result_a = await task_a; - result_a.MatchSnapshot("DispatchMultipleQueriesAndRewriteErrors_A"); - - IExecutionResult result_b = await task_b; - result_b.MatchSnapshot("DispatchMultipleQueriesAndRewriteErrors_B"); - } - - [Fact] - public async Task DispatchMultipleQueriesWithGlobalError() - { - // arrange - string query = null; - int count = 0; - - var result = QueryResultBuilder.New(); - var data = new OrderedDictionary(); - data["__0__a"] = "a"; - data["__1__a"] = "b"; - data["__1__b"] = "c"; - result.SetData(data); - result.AddError(ErrorBuilder.New() - .SetMessage("foo") - .Build()); - - var executor = new Mock(); - executor.Setup(t => t.ExecuteAsync( - It.IsAny(), - It.IsAny())) - .Returns(new Func>((r, ct) => - { - count++; - query = r.Query.ToString(); - return Task.FromResult(result.Create()); - })); - - var request_a = QueryRequestBuilder.Create("query a { a }"); - var request_b = QueryRequestBuilder.Create("query b { a b }"); - - var client = new RemoteRequestExecutor( - new EmptyServiceProvider(), - executor.Object); - - // act - Task task_a = client.ExecuteAsync(request_a); - Task task_b = client.ExecuteAsync(request_b); - await client.DispatchAsync(CancellationToken.None); - - // assert - Assert.Equal(1, count); - - IExecutionResult result_a = await task_a; - result_a.MatchSnapshot("DispatchMultipleQueriesWithGlobalError_A"); - - IExecutionResult result_b = await task_b; - result_b.MatchSnapshot("DispatchMultipleQueriesWithGlobalError_B"); - } - - [Fact] - public async Task DispatchMultipleQueriesWithGlobalException() - { - // arrange - var executor = new Mock(); - executor.Setup(t => t.ExecuteAsync( - It.IsAny(), - It.IsAny())) - .Returns(new Func>((r, ct) => - { - return Task.FromException( - new Exception("foo")); - })); - - var request_a = QueryRequestBuilder.Create("query a { a }"); - var request_b = QueryRequestBuilder.Create("query b { a b }"); - - var client = new RemoteRequestExecutor( - new EmptyServiceProvider(), - executor.Object); - - // act - Task task_a = client.ExecuteAsync(request_a); - Task task_b = client.ExecuteAsync(request_b); - await client.DispatchAsync(CancellationToken.None); - - // assert - Assert.Equal("foo", - (await Assert.ThrowsAsync(() => task_a)).Message); - Assert.Equal("foo", - (await Assert.ThrowsAsync(() => task_b)).Message); - } - - [Fact] - public async Task DispatchMultipleQueriesWithVariables() - { - // arrange - IReadOnlyQueryRequest mergedRequest = null; - int count = 0; - - var result = QueryResultBuilder.New(); - var data = new OrderedDictionary(); - data["__0__a"] = "a"; - data["__1__a"] = "b"; - data["__1__b"] = "c"; - result.SetData(data); - - var schema = SchemaBuilder.New() - .AddDocumentFromString("type Query { foo: String }") - .AddResolver("Query", "foo", c => "bar") - .Create(); - - var executor = new Mock(); - executor.Setup(t => t.ExecuteAsync( - It.IsAny(), - It.IsAny())) - .Returns(new Func>((r, ct) => - { - count++; - mergedRequest = r; - return Task.FromResult(result.Create()); - })); - executor.Setup(t => t.Schema).Returns(schema); - - var request_a = QueryRequestBuilder.New() - .SetQuery("query a($a: String) { a(b: $a) }") - .SetVariableValue("a", "foo") - .Create(); - - var request_b = QueryRequestBuilder.Create( - "query b { a b }"); - - var client = new RemoteRequestExecutor( - new EmptyServiceProvider(), - executor.Object); - - // act - Task task_a = client.ExecuteAsync(request_a); - Task task_b = client.ExecuteAsync(request_b); - await client.DispatchAsync(CancellationToken.None); - - // assert - await task_a; - await task_b; - - Assert.Equal(1, count); - new - { - Query = mergedRequest.Query.ToString(), - QueryName = mergedRequest.QueryName, - QueryHash = mergedRequest.QueryHash, - OperationName = mergedRequest.OperationName, - Varables = mergedRequest.VariableValues, - Extensions = mergedRequest.Extensions, - }.MatchSnapshot(); - } - } -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/StitchingContextTests.txt b/src/HotChocolate/Stitching/test/Stitching.Tests/Client/StitchingContextTests.txt deleted file mode 100644 index fda77f7dfd5..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/StitchingContextTests.txt +++ /dev/null @@ -1,109 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Net.Http; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.DependencyInjection; -using HotChocolate.AspNetCore; -using HotChocolate.AspNetCore.Tests.Utilities; -using HotChocolate.Execution; -using HotChocolate.Stitching.Requests; -using Moq; -using Snapshooter.Xunit; -using Xunit; - -namespace HotChocolate.Stitching.Client -{ - public class StitchingContextTests : StitchingTestBase - { - public StitchingContextTests( - TestServerFactory testServerFactory) - : base(testServerFactory) - { - } - - [Fact] - public async Task String_Variable_Is_Converted_To_String_Literal() - { - // arrange - var serviceCollection = new ServiceCollection(); - serviceCollection.AddSingleton(CreateRemoteSchemas()); - serviceCollection.AddStitchedSchema(builder => builder - .AddSchemaFromHttp("contract") - .AddSchemaFromHttp("customer")); - - IServiceProvider services = serviceCollection.BuildServiceProvider(); - - IStitchingContext stitchingContext = services.GetRequiredService(); - IRemoteRequestExecutor customerRequestExecutor = stitchingContext.GetRemoteQueryClient("customer"); - - IReadOnlyQueryRequest request = QueryRequestBuilder.New() - .SetQuery("query ($id: ID!) { customer(id: $id) { name } }") - .SetVariableValue("id", "Q3VzdG9tZXIKZDE=") - .Create(); - - Task executeTask = customerRequestExecutor.ExecuteAsync(request); - await customerRequestExecutor.DispatchAsync(CancellationToken.None); - - IExecutionResult result = await executeTask; - - result.MatchSnapshot(); - } - - [Fact] - public async Task Int_Variable_Is_Converted_To_Int_Literal() - { - // arrange - var serviceCollection = new ServiceCollection(); - serviceCollection.AddSingleton(CreateFooServer()); - serviceCollection.AddStitchedSchema(builder => builder - .AddSchemaFromString("foo", "type Query { foo(a: Int!) : Int! }")); - - IServiceProvider services = serviceCollection.BuildServiceProvider(); - - IStitchingContext stitchingContext = services.GetRequiredService(); - IRemoteRequestExecutor customerRequestExecutor = stitchingContext.GetRemoteQueryClient("foo"); - - IReadOnlyQueryRequest request = QueryRequestBuilder.New() - .SetQuery("query ($foo: Int!) { foo(a: $foo) }") - .SetVariableValue("foo", 1) - .Create(); - - Task executeTask = customerRequestExecutor.ExecuteAsync(request); - await customerRequestExecutor.DispatchAsync(CancellationToken.None); - - IExecutionResult result = await executeTask; - - result.MatchSnapshot(); - } - - private IHttpClientFactory CreateFooServer() - { - var connections = new Dictionary(); - - TestServer foo = TestServerFactory.Create( - services => services.AddGraphQL( - SchemaBuilder.New() - .AddDocumentFromString("type Query { foo(a: Int!) : Int! }") - .AddResolver("Query", "foo", ctx => ctx.Argument("a"))), - app => app.UseGraphQL()); - - connections["foo"] = foo.CreateClient(); - - var httpClientFactory = new Mock(); - httpClientFactory.Setup(t => t.CreateClient(It.IsAny())) - .Returns(new Func(n => - { - if (connections.ContainsKey(n)) - { - return connections[n]; - } - - throw new Exception(); - })); - - return httpClientFactory.Object; - } - } -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueriesAndRewriteErrors_A.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueriesAndRewriteErrors_A.snap deleted file mode 100644 index ee281b20614..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueriesAndRewriteErrors_A.snap +++ /dev/null @@ -1,8 +0,0 @@ -{ - "Data": { - "a": "a" - }, - "Errors": null, - "Extensions": null, - "ContextData": null -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueriesAndRewriteErrors_B.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueriesAndRewriteErrors_B.snap deleted file mode 100644 index 07c607a0df1..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueriesAndRewriteErrors_B.snap +++ /dev/null @@ -1,20 +0,0 @@ -{ - "Data": { - "a": "b", - "b": "c" - }, - "Errors": [ - { - "Message": "foo", - "Code": null, - "Path": [ - "b" - ], - "Locations": [], - "Exception": null, - "Extensions": {} - } - ], - "Extensions": null, - "ContextData": null -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueriesDistinctOperationName_MergedQuery.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueriesDistinctOperationName_MergedQuery.snap deleted file mode 100644 index 9f646175582..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueriesDistinctOperationName_MergedQuery.snap +++ /dev/null @@ -1 +0,0 @@ -query a { __0__a: a __1__a: a __1__b: b } diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueriesDistinctOperationName_Result_A.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueriesDistinctOperationName_Result_A.snap deleted file mode 100644 index ee281b20614..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueriesDistinctOperationName_Result_A.snap +++ /dev/null @@ -1,8 +0,0 @@ -{ - "Data": { - "a": "a" - }, - "Errors": null, - "Extensions": null, - "ContextData": null -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueriesDistinctOperationName_Result_B.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueriesDistinctOperationName_Result_B.snap deleted file mode 100644 index c4919d68eae..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueriesDistinctOperationName_Result_B.snap +++ /dev/null @@ -1,9 +0,0 @@ -{ - "Data": { - "a": "b", - "b": "c" - }, - "Errors": null, - "Extensions": null, - "ContextData": null -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueriesWithGlobalError_A.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueriesWithGlobalError_A.snap deleted file mode 100644 index ee281b20614..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueriesWithGlobalError_A.snap +++ /dev/null @@ -1,8 +0,0 @@ -{ - "Data": { - "a": "a" - }, - "Errors": null, - "Extensions": null, - "ContextData": null -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueriesWithGlobalError_B.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueriesWithGlobalError_B.snap deleted file mode 100644 index 2d9f64b2fb3..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueriesWithGlobalError_B.snap +++ /dev/null @@ -1,18 +0,0 @@ -{ - "Data": { - "a": "b", - "b": "c" - }, - "Errors": [ - { - "Message": "foo", - "Code": null, - "Path": null, - "Locations": [], - "Exception": null, - "Extensions": {} - } - ], - "Extensions": null, - "ContextData": null -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueries_MergedQuery.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueries_MergedQuery.snap deleted file mode 100644 index 13c8ce25ef6..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueries_MergedQuery.snap +++ /dev/null @@ -1 +0,0 @@ -query exec_batch { __0__a: a __1__a: a __1__b: b } diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueries_Result_A.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueries_Result_A.snap deleted file mode 100644 index ee281b20614..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueries_Result_A.snap +++ /dev/null @@ -1,8 +0,0 @@ -{ - "Data": { - "a": "a" - }, - "Errors": null, - "Extensions": null, - "ContextData": null -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueries_Result_B.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueries_Result_B.snap deleted file mode 100644 index c4919d68eae..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/DispatchMultipleQueries_Result_B.snap +++ /dev/null @@ -1,9 +0,0 @@ -{ - "Data": { - "a": "b", - "b": "c" - }, - "Errors": null, - "Extensions": null, - "ContextData": null -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/RemoteQueryClientTests.DispatchMultipleQueriesWithVariables.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/RemoteQueryClientTests.DispatchMultipleQueriesWithVariables.snap deleted file mode 100644 index d6fb5c6a353..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/RemoteQueryClientTests.DispatchMultipleQueriesWithVariables.snap +++ /dev/null @@ -1,15 +0,0 @@ -{ - "Query": "query exec_batch($__0__a: String) { __0__a: a(b: $__0__a) __1__a: a __1__b: b }", - "QueryName": null, - "QueryHash": null, - "OperationName": "exec_batch", - "Varables": { - "__0__a": { - "Kind": "StringValue", - "Location": null, - "Value": "foo", - "Block": false - } - }, - "Extensions": {} -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/RemoteQueryClientTests.DispatchSingleQuery.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/RemoteQueryClientTests.DispatchSingleQuery.snap deleted file mode 100644 index 54a34b163c3..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/RemoteQueryClientTests.DispatchSingleQuery.snap +++ /dev/null @@ -1 +0,0 @@ -{ a } diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/StitchingContextTests.Int_Variable_Is_Converted_To_Int_Literal.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/StitchingContextTests.Int_Variable_Is_Converted_To_Int_Literal.snap deleted file mode 100644 index 065987c28d3..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/StitchingContextTests.Int_Variable_Is_Converted_To_Int_Literal.snap +++ /dev/null @@ -1,8 +0,0 @@ -{ - "Data": { - "foo": 1 - }, - "Errors": null, - "Extensions": null, - "ContextData": null -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/StitchingContextTests.String_Variable_Is_Converted_To_String_Literal.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/StitchingContextTests.String_Variable_Is_Converted_To_String_Literal.snap deleted file mode 100644 index 017aaed5611..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Client/__snapshots__/StitchingContextTests.String_Variable_Is_Converted_To_String_Literal.snap +++ /dev/null @@ -1,10 +0,0 @@ -{ - "Data": { - "customer": { - "name": "Freddy Freeman" - } - }, - "Errors": null, - "Extensions": null, - "ContextData": null -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Integration/FederatedRedisSchemaTests.cs b/src/HotChocolate/Stitching/test/Stitching.Tests/Integration/FederatedRedisSchemaTests.cs index 1da595aca34..a15f8f4389f 100644 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Integration/FederatedRedisSchemaTests.cs +++ b/src/HotChocolate/Stitching/test/Stitching.Tests/Integration/FederatedRedisSchemaTests.cs @@ -2,10 +2,10 @@ using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; -using ChilliCream.Testing; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; +using ChilliCream.Testing; using HotChocolate.AspNetCore.Utilities; using HotChocolate.Execution; using HotChocolate.Stitching.Schemas.Accounts; diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Integration/FederatedSchemaErrorTests.cs b/src/HotChocolate/Stitching/test/Stitching.Tests/Integration/FederatedSchemaErrorTests.cs new file mode 100644 index 00000000000..7c2a455b6f3 --- /dev/null +++ b/src/HotChocolate/Stitching/test/Stitching.Tests/Integration/FederatedSchemaErrorTests.cs @@ -0,0 +1,250 @@ +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using HotChocolate.AspNetCore.Utilities; +using HotChocolate.Execution; +using HotChocolate.Stitching.Schemas.Accounts; +using HotChocolate.Stitching.Schemas.Inventory; +using HotChocolate.Stitching.Schemas.Products; +using HotChocolate.Stitching.Schemas.Reviews; +using HotChocolate.Types; +using Snapshooter.Xunit; +using Xunit; +using HotChocolate.Language; +using Snapshooter; + +namespace HotChocolate.Stitching.Integration +{ + public class FederatedSchemaErrorTests : IClassFixture + { + private const string _accounts = "accounts"; + private const string _inventory = "inventory"; + private const string _products = "products"; + private const string _reviews = "reviews"; + + public FederatedSchemaErrorTests(StitchingTestContext context) + { + Context = context; + } + + private StitchingTestContext Context { get; } + + [Fact] + public async Task AutoMerge_Schema() + { + // arrange + IHttpClientFactory httpClientFactory = CreateDefaultRemoteSchemas(); + + // act + ISchema schema = + await new ServiceCollection() + .AddSingleton(httpClientFactory) + .AddGraphQL() + .AddQueryType(d => d.Name("Query")) + .AddRemoteSchema(_accounts) + .AddRemoteSchema(_inventory) + .AddRemoteSchema(_products) + .AddRemoteSchema(_reviews) + .BuildSchemaAsync(); + + // assert + schema.Print().MatchSnapshot(); + } + + [Fact] + public async Task Execute_Error_StatusCode_On_DownStream_Request() + { + // arrange + IHttpClientFactory httpClientFactory = CreateDefaultRemoteSchemas(); + + IRequestExecutor executor = + await new ServiceCollection() + .AddSingleton(httpClientFactory) + .AddGraphQL() + .AddQueryType(d => d.Name("Query")) + .AddRemoteSchema(_accounts) + .AddRemoteSchema(_inventory) + .AddRemoteSchema(_products) + .AddRemoteSchema(_reviews) + .BuildRequestExecutorAsync(); + + // act + IExecutionResult result = await executor.ExecuteAsync( + @"{ + error + }"); + + // assert + result.ToJson().MatchSnapshot(); + } + + [Fact] + public async Task Execute_Ok_StatusCode_With_Error_On_DownStream_Request() + { + // arrange + IHttpClientFactory httpClientFactory = CreateDefaultRemoteSchemas(); + + IRequestExecutor executor = + await new ServiceCollection() + .AddSingleton(httpClientFactory) + .AddGraphQL() + .AddQueryType(d => d.Name("Query")) + .AddRemoteSchema(_accounts) + .AddRemoteSchema(_inventory) + .AddRemoteSchema(_products) + .AddRemoteSchema(_reviews) + .BuildRequestExecutorAsync(); + + // act + IExecutionResult result = await executor.ExecuteAsync( + @"{ + a: topProducts(first: 1) { + upc + error + } + b: topProducts(first: 2) { + upc + error + } + }"); + + // assert + Assert.Collection( + result.Errors!.Select(t => t.Path!.ToString()).OrderBy(t => t), + t => Assert.Equal("/a[0]/error", t), + t => Assert.Equal("/b[0]/error", t), + t => Assert.Equal("/b[1]/error", t)); + + } + + public TestServer CreateAccountsService() => + Context.ServerFactory.Create( + services => services + .AddRouting() + .AddHttpRequestSerializer(HttpResultSerialization.JsonArray) + .AddGraphQLServer() + .AddAccountsSchema() + .PublishSchemaDefinition(c => c + .SetName(_accounts) + .IgnoreRootTypes() + .AddTypeExtensionsFromString( + @"extend type Query { + me: User! @delegate(path: ""user(id: 1)"") + } + + extend type Review { + author: User @delegate(path: ""user(id: $fields:authorId)"") + }")), + app => app + .UseWebSockets() + .UseRouting() + .UseEndpoints(endpoints => endpoints.MapGraphQL("/"))); + + public TestServer CreateInventoryService() => + Context.ServerFactory.Create( + services => services + .AddRouting() + .AddHttpRequestSerializer(HttpResultSerialization.JsonArray) + .AddGraphQLServer() + .AddInventorySchema() + .PublishSchemaDefinition(c => c + .SetName(_inventory) + .IgnoreRootTypes() + .AddTypeExtensionsFromString( + @"extend type Product { + inStock: Boolean + @delegate(path: ""inventoryInfo(upc: $fields:upc).isInStock"") + shippingEstimate: Int + @delegate(path: ""shippingEstimate(price: $fields:price weight: $fields:weight)"") + }")), + app => app + .UseWebSockets() + .UseRouting() + .UseEndpoints(endpoints => endpoints.MapGraphQL("/"))); + + public TestServer CreateProductsService() => + Context.ServerFactory.Create( + services => services + .AddRouting() + .AddHttpRequestSerializer(HttpResultSerialization.JsonArray) + .AddGraphQLServer() + .AddProductsSchema() + .AddTypeExtension(new ObjectTypeExtension(d => + { + d.Name("Query") + .Field("error") + .Type(new NonNullTypeNode(new NamedTypeNode("String"))) + .Resolve(() => throw new GraphQLException("error_message_query")); + })) + .AddTypeExtension(new ObjectTypeExtension(d => + { + d.Name("Product") + .Field("error") + .Type(new NamedTypeNode("String")) + .Resolve(ctx => throw new GraphQLException( + ErrorBuilder.New() + .SetMessage("error_message_product") + .SetPath(ctx.Path) + .Build())); + })) + .PublishSchemaDefinition(c => c + .SetName(_products) + .IgnoreRootTypes() + .AddTypeExtensionsFromString( + @"extend type Query { + topProducts(first: Int = 5): [Product] @delegate + auth: String! @delegate + error: String! @delegate + } + + extend type Review { + product: Product @delegate(path: ""product(upc: $fields:upc)"") + }")), + app => app + .UseWebSockets() + .UseRouting() + .UseEndpoints(endpoints => endpoints.MapGraphQL("/"))); + + public TestServer CreateReviewsService() => + Context.ServerFactory.Create( + services => services + .AddRouting() + .AddHttpRequestSerializer(HttpResultSerialization.JsonArray) + .AddGraphQLServer() + .AddReviewSchema() + .PublishSchemaDefinition(c => c + .SetName(_reviews) + .IgnoreRootTypes() + .AddTypeExtensionsFromString( + @"extend type User { + reviews: [Review] + @delegate(path:""reviewsByAuthor(authorId: $fields:id)"") + } + + extend type Product { + reviews: [Review] + @delegate(path:""reviewsByProduct(upc: $fields:upc)"") + }")), + app => app + .UseWebSockets() + .UseRouting() + .UseEndpoints(endpoints => endpoints.MapGraphQL("/"))); + + public IHttpClientFactory CreateDefaultRemoteSchemas() + { + var connections = new Dictionary + { + { _accounts, CreateAccountsService().CreateClient() }, + { _inventory, CreateInventoryService().CreateClient() }, + { _products, CreateProductsService().CreateClient() }, + { _reviews, CreateReviewsService().CreateClient() }, + }; + + return StitchingTestContext.CreateRemoteSchemas(connections); + } + } +} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Integration/FederatedSchemaTests.cs b/src/HotChocolate/Stitching/test/Stitching.Tests/Integration/FederatedSchemaTests.cs index a7f88d24128..4a5dd51bab7 100644 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Integration/FederatedSchemaTests.cs +++ b/src/HotChocolate/Stitching/test/Stitching.Tests/Integration/FederatedSchemaTests.cs @@ -28,7 +28,7 @@ public FederatedSchemaTests(StitchingTestContext context) Context = context; } - protected StitchingTestContext Context { get; } + private StitchingTestContext Context { get; } [Fact] public async Task AutoMerge_Schema() diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Integration/__snapshots__/BaseTests.Foo.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Integration/__snapshots__/BaseTests.Foo.snap deleted file mode 100644 index a6eec08a665..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Integration/__snapshots__/BaseTests.Foo.snap +++ /dev/null @@ -1,27 +0,0 @@ -{ - "errors": [ - { - "message": "Unexpected Execution Error", - "locations": [ - { - "line": 6, - "column": 19 - } - ], - "path": [ - "topProducts" - ], - "extensions": { - "message": "There is no schema with the given name \u0060Products\u0060.", - "stackTrace": " at HotChocolate.Stitching.Requests.StitchingContext.GetRemoteRequestExecutor(NameString schemaName) in /Users/michael/GitHub/hc/src/HotChocolate/Stitching/src/Stitching/Requests/StitchingContext.cs:line 50\n at HotChocolate.Stitching.Requests.StitchingContext.GetRemoteSchema(NameString schemaName) in /Users/michael/GitHub/hc/src/HotChocolate/Stitching/src/Stitching/Requests/StitchingContext.cs:line 57\n at HotChocolate.Stitching.Delegation.DelegateToRemoteSchemaMiddleware.ResolveScopedVariables(IResolverContext context, NameString schemaName, OperationType operationType, IImmutableStack\u00601 reversePath, ExtractFieldQuerySyntaxRewriter rewriter) in /Users/michael/GitHub/hc/src/HotChocolate/Stitching/src/Stitching/Delegation/DelegateToRemoteSchemaMiddleware.cs:line 326\n at HotChocolate.Stitching.Delegation.DelegateToRemoteSchemaMiddleware.CreateQuery(IMiddlewareContext context, NameString schemaName, IImmutableStack\u00601 path, IImmutableStack\u00601 reversePath) in /Users/michael/GitHub/hc/src/HotChocolate/Stitching/src/Stitching/Delegation/DelegateToRemoteSchemaMiddleware.cs:line 116\n at HotChocolate.Stitching.Delegation.DelegateToRemoteSchemaMiddleware.InvokeAsync(IMiddlewareContext context) in /Users/michael/GitHub/hc/src/HotChocolate/Stitching/src/Stitching/Delegation/DelegateToRemoteSchemaMiddleware.cs:line 57\n at HotChocolate.Utilities.MiddlewareCompiler\u00601.ExpressionHelper.AwaitTaskHelper(Task task) in /Users/michael/GitHub/hc/src/HotChocolate/Utilities/src/Utilities/MiddlewareCompiler.cs:line 167\n at HotChocolate.Execution.Processing.ResolverTask.ExecuteResolverPipelineAsync() in /Users/michael/GitHub/hc/src/HotChocolate/Core/src/Execution/Processing/ResolverTask.cs:line 65\n at HotChocolate.Execution.Processing.ResolverTask.TryExecuteAsync() in /Users/michael/GitHub/hc/src/HotChocolate/Core/src/Execution/Processing/ResolverTask.cs:line 51" - } - } - ], - "data": { - "me": { - "name": "Ada Lovelace", - "birthdate": "1815-12-10T00:00:00.000\u002B00:35" - }, - "topProducts": null - } -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Integration/__snapshots__/FederatedSchemaErrorTests.AutoMerge_Schema.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Integration/__snapshots__/FederatedSchemaErrorTests.AutoMerge_Schema.snap new file mode 100644 index 00000000000..a9161ac1336 --- /dev/null +++ b/src/HotChocolate/Stitching/test/Stitching.Tests/Integration/__snapshots__/FederatedSchemaErrorTests.AutoMerge_Schema.snap @@ -0,0 +1,71 @@ +schema { + query: Query +} + +type InventoryInfo @source(name: "InventoryInfo", schema: "inventory") { + upc: Int! + isInStock: Boolean! +} + +type Product @source(name: "Product", schema: "products") { + upc: Int! + name: String + price: Int! + weight: Int! + error: String + inStock: Boolean @delegate(path: "inventoryInfo(upc: $fields:upc).isInStock", schema: "inventory") + shippingEstimate: Int @delegate(path: "shippingEstimate(price: $fields:price weight: $fields:weight)", schema: "inventory") + reviews: [Review] @delegate(path: "reviewsByProduct(upc: $fields:upc)", schema: "reviews") +} + +type Query { + me: User! @delegate(path: "user(id: 1)", schema: "accounts") + topProducts(first: Int = 5): [Product] @delegate(schema: "products") + auth: String! @delegate(schema: "products") + error: String! @delegate(schema: "products") +} + +type Review @source(name: "Review", schema: "reviews") { + id: Int! + authorId: Int! + upc: Int! + body: String + author: User @delegate(path: "user(id: $fields:authorId)", schema: "accounts") + product: Product @delegate(path: "product(upc: $fields:upc)", schema: "products") +} + +type User @source(name: "User", schema: "accounts") { + id: Int! + name: String + birthdate: DateTime! + username: String + reviews: [Review] @delegate(path: "reviewsByAuthor(authorId: $fields:id)", schema: "reviews") +} + +directive @computed("Specifies the fields on which a computed field is dependent on." dependantOn: [Name!]) on FIELD_DEFINITION + +"The `@defer` directive may be provided for fragment spreads and inline fragments to inform the executor to delay the execution of the current fragment to indicate deprioritization of the current fragment. A query with `@defer` directive will cause the request to potentially return multiple responses, where non-deferred data is delivered in the initial response and data deferred is delivered in a subsequent response. `@include` and `@skip` take precedence over `@defer`." +directive @defer("If this argument label has a value other than null, it will be passed on to the result of this defer directive. This label is intended to give client applications a way to identify to which fragment a deferred result belongs to." label: String "Deferred when true." if: Boolean) on FRAGMENT_SPREAD | INLINE_FRAGMENT + +directive @delegate(path: String "The name of the schema to which this field shall be delegated to." schema: Name!) on FIELD_DEFINITION + +"The @deprecated directive is used within the type system definition language to indicate deprecated portions of a GraphQL service’s schema,such as deprecated fields on a type or deprecated enum values." +directive @deprecated("Deprecations include a reason for why it is deprecated, which is formatted using Markdown syntax (as specified by CommonMark)." reason: String = "No longer supported") on FIELD_DEFINITION | ENUM_VALUE + +"Directs the executor to include this field or fragment only when the `if` argument is true." +directive @include("Included when true." if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT + +"Directs the executor to skip this field or fragment when the `if` argument is true." +directive @skip("Skipped when true." if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT + +"Annotates the original name of a type." +directive @source("The original name of the annotated type." name: Name! "The name of the schema to which this type belongs to." schema: Name!) repeatable on ENUM | OBJECT | INTERFACE | UNION | INPUT_OBJECT | FIELD_DEFINITION | INPUT_FIELD_DEFINITION | ARGUMENT_DEFINITION | ENUM_VALUE + +"The `@stream` directive may be provided for a field of `List` type so that the backend can leverage technology such as asynchronous iterators to provide a partial list in the initial response, and additional list items in subsequent responses. `@include` and `@skip` take precedence over `@stream`." +directive @stream("If this argument label has a value other than null, it will be passed on to the result of this stream directive. This label is intended to give client applications a way to identify to which fragment a streamed result belongs to." label: String "The initial elements that shall be send down to the consumer." initialCount: Int! "Streamed when true." if: Boolean!) on FIELD + +"The `DateTime` scalar represents an ISO-8601 compliant date time type." +scalar DateTime + +"The name scalar represents a valid GraphQL name as specified in the spec and can be used to refer to fields or types." +scalar Name diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Integration/__snapshots__/FederatedSchemaErrorTests.Execute_Error_StatusCode_On_DownStream_Request.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Integration/__snapshots__/FederatedSchemaErrorTests.Execute_Error_StatusCode_On_DownStream_Request.snap new file mode 100644 index 00000000000..2e6c9e67bd5 --- /dev/null +++ b/src/HotChocolate/Stitching/test/Stitching.Tests/Integration/__snapshots__/FederatedSchemaErrorTests.Execute_Error_StatusCode_On_DownStream_Request.snap @@ -0,0 +1,13 @@ +{ + "errors": [ + { + "message": "error_message_query", + "extensions": { + "remote": { + "message": "error_message_query" + }, + "schemaName": "products" + } + } + ] +} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Schemas/Products/ProductRepository.cs b/src/HotChocolate/Stitching/test/Stitching.Tests/Schemas/Products/ProductRepository.cs index 2cd0af8ee22..9124c7a6b59 100644 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Schemas/Products/ProductRepository.cs +++ b/src/HotChocolate/Stitching/test/Stitching.Tests/Schemas/Products/ProductRepository.cs @@ -17,6 +17,7 @@ public ProductRepository() }.ToDictionary(t => t.Upc); } + [GraphQLNonNullType] public IEnumerable GetTopProducts(int first) => _products.Values.OrderBy(t => t.Upc).Take(first); diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/ExtractFieldQuerySyntaxRewriterTests.txt b/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/ExtractFieldQuerySyntaxRewriterTests.txt deleted file mode 100644 index 8f40f2af52e..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/ExtractFieldQuerySyntaxRewriterTests.txt +++ /dev/null @@ -1,193 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; -using ChilliCream.Testing; -using HotChocolate.Language; -using HotChocolate.Stitching.Delegation; -using HotChocolate.Stitching.Utilities; -using HotChocolate.Types; -using Snapshooter; -using Snapshooter.Xunit; -using Xunit; - -namespace HotChocolate.Stitching -{ - public class ExtractFieldQuerySyntaxRewriterTests - { - [InlineData("Stitching.graphql", "StitchingQuery.graphql")] - [InlineData("Stitching.graphql", "StitchingQueryWithFragmentDefs.graphql")] - [InlineData("Stitching.graphql", "StitchingQueryWithInlineFragment.graphql")] - [InlineData("Stitching.graphql", "StitchingQueryWithUnion.graphql")] - [InlineData("Stitching.graphql", "StitchingQueryWithVariables.graphql")] - [InlineData("Stitching.graphql", "StitchingQueryWithArguments.graphql")] - [InlineData("Stitching.graphql", "StitchingQueryWithTypename.graphql")] - [InlineData("StitchingComputed.graphql", "StitchingQueryComputedField.graphql")] - [Theory] - public void ExtractField(string schemaFile, string queryFile) - { - // arrange - ISchema schema = Schema.Create( - FileResource.Open(schemaFile), - c => - { - c.RegisterType(); - c.RegisterDirective(); - c.RegisterDirective(); - c.Use(next => context => Task.CompletedTask); - }); - - DocumentNode query = Utf8GraphQLParser.Parse( - FileResource.Open(queryFile)); - - OperationDefinitionNode operation = query.Definitions - .OfType().Single(); - - FieldNode selection = operation - .SelectionSet.Selections - .OfType().First(); - - // act - var rewriter = new ExtractFieldQuerySyntaxRewriter(schema, - Array.Empty()); - ExtractedField extractedField = rewriter.ExtractField( - "customer", query, operation, selection, - schema.GetType("Query")); - - // assert - DocumentNode document = RemoteQueryBuilder.New() - .SetRequestField(extractedField.Field) - .AddFragmentDefinitions(extractedField.Fragments) - .AddVariables(extractedField.Variables) - .Build(); - - QuerySyntaxSerializer.Serialize(document) - .MatchSnapshot(new SnapshotNameExtension( - schemaFile, queryFile)); - } - - [Fact] - public void ExtractField_WithCustomRewriters() - { - // arrange - ISchema schema = Schema.Create( - FileResource.Open("Stitching.graphql"), - c => - { - c.RegisterType(); - c.RegisterDirective(); - c.RegisterDirective(); - c.Use(next => context => Task.CompletedTask); - }); - - DocumentNode query = Utf8GraphQLParser.Parse( - FileResource.Open("StitchingQuery.graphql")); - - OperationDefinitionNode operation = query.Definitions - .OfType().Single(); - - FieldNode selection = operation - .SelectionSet.Selections - .OfType().First(); - - var rewriters = new List - { - new DummyRewriter() - }; - - // act - var rewriter = new ExtractFieldQuerySyntaxRewriter( - schema, rewriters); - - ExtractedField extractedField = rewriter.ExtractField( - "customer", query, operation, selection, - schema.GetType("Query")); - - // assert - DocumentNode document = RemoteQueryBuilder.New() - .SetRequestField(extractedField.Field) - .AddFragmentDefinitions(extractedField.Fragments) - .AddVariables(extractedField.Variables) - .Build(); - - QuerySyntaxSerializer.Serialize(document) - .MatchSnapshot(); - } - - [InlineData("Stitching.graphql", "StitchingQueryWithSkip.graphql")] - [Theory] - public void ExtractFieldWithDirective(string schemaFile, string queryFile) - { - // arrange - ISchema schema = Schema.Create( - FileResource.Open(schemaFile), - c => - { - c.RegisterType(); - c.RegisterDirective(); - c.RegisterDirective(); - c.Use(next => context => Task.CompletedTask); - }); - - DocumentNode query = Utf8GraphQLParser.Parse( - FileResource.Open(queryFile)); - - OperationDefinitionNode operation = query.Definitions - .OfType().Single(); - - FieldNode selection = operation - .SelectionSet.Selections - .OfType().First(); - - // act - var rewriter = new ExtractFieldQuerySyntaxRewriter(schema, - Array.Empty()); - ExtractedField extractedField = rewriter.ExtractField( - "customer", query, operation, selection, - schema.GetType("Query")); - - // assert - DocumentNode document = RemoteQueryBuilder.New() - .SetRequestField(extractedField.Field) - .AddFragmentDefinitions(extractedField.Fragments) - .AddVariables(extractedField.Variables) - .Build(); - - QuerySyntaxSerializer.Serialize(document) - .MatchSnapshot(new SnapshotNameExtension( - schemaFile, queryFile)); - } - - private class DummyRewriter - : QueryDelegationRewriterBase - { - public override FieldNode OnRewriteField( - NameString targetSchemaName, - IOutputType outputType, - IOutputField outputField, - FieldNode field) - { - return field.WithAlias(new NameNode("foo_bar")); - } - - public override SelectionSetNode OnRewriteSelectionSet( - NameString targetSchemaName, - IOutputType outputType, - IOutputField outputField, - SelectionSetNode selectionSet) - { - return selectionSet.AddSelection( - new FieldNode - ( - null, - new NameNode("abc_def"), - null, - Array.Empty(), - Array.Empty(), - null - )); - } - } - } -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/FieldDependencyResolverTests.txt b/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/FieldDependencyResolverTests.txt deleted file mode 100644 index 719a71256c2..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/FieldDependencyResolverTests.txt +++ /dev/null @@ -1,49 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Xunit; -using Snapshooter.Xunit; -using HotChocolate.Language; -using HotChocolate.Stitching.Utilities; -using HotChocolate.Types; -using FileResource = ChilliCream.Testing.FileResource; -using System.Text.Json; - -namespace HotChocolate.Stitching -{ - public class FieldDependencyResolverTests - { - [Fact] - public void GetFieldDependencies() - { - // arrange - ISchema schema = Schema.Create( - FileResource.Open("Stitching.graphql"), - c => - { - c.RegisterType(); - c.RegisterDirective(); - c.Use(next => context => Task.CompletedTask); - }); - - DocumentNode query = Utf8GraphQLParser.Parse( - FileResource.Open("StitchingQuery.graphql")); - - FieldNode selection = query.Definitions - .OfType().Single() - .SelectionSet.Selections - .OfType().Single(); - - // act - var fieldDependencyResolver = new FieldDependencyResolver(schema); - ISet dependencies = fieldDependencyResolver - .GetFieldDependencies( - query, - selection, - schema.GetType("Customer")); - - // assert - Snapshot.Match(dependencies); - } - } -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/HttpQueryClientTests.txt b/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/HttpQueryClientTests.txt deleted file mode 100644 index 6d02c63ef49..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/HttpQueryClientTests.txt +++ /dev/null @@ -1,104 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Net.Http; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using HotChocolate.Execution; -using HotChocolate.Language; -using HotChocolate.Stitching.Pipeline; -using Moq; -using Newtonsoft.Json; -using Xunit; - -namespace HotChocolate.Stitching.Utilities -{ - public class HttpQueryClientTests - { - private readonly HttpRequestClient sut; - - public HttpQueryClientTests() - { - sut = new HttpRequestClient(); - } - - [Fact] - public async Task FetchAsync_Sends_Valid_Json_Request() - { - // arrange - var messageHandler = new FakeMessageHandler(); - - var httpClient = new HttpClient(messageHandler) - { - BaseAddress = new Uri("http://some.url") - }; - - IReadOnlyQueryRequest query = QueryRequestBuilder.New() - .SetQuery( - @"query aQuery { - foo - bar - }") - .AddVariableValue("strVar", new StringValueNode("some-string")) - .AddVariableValue("intVal", new IntValueNode(42)) - .AddVariableValue("floatVal", new FloatValueNode(1.23m)) - .AddVariableValue("boolVal", new BooleanValueNode(true)) - .AddVariableValue("listVal", - new ListValueNode( - new ReadOnlyCollection( - new List - { - new FloatValueNode(1.23m), - new FloatValueNode(1.80m), - new FloatValueNode(2.80m) - }) )) - .AddVariableValue("listStringVal", - new ListValueNode( - new ReadOnlyCollection( - new List - { - new StringValueNode("a"), - new StringValueNode("b"), - new StringValueNode("c") - }))) - .AddVariableValue("enumVal", new EnumValueNode(System.Net.HttpStatusCode.OK)) - .AddVariableValue("otherStrVar", new StringValueNode("some-other-string")) - .Create(); - - // act - await sut.FetchAsync( - query, - httpClient); - - // assert - try - { - dynamic requestObj = JsonConvert.DeserializeObject(messageHandler.requestBody); - Assert.NotNull(requestObj); - Assert.NotNull(requestObj.query); - Assert.NotNull(requestObj.variables); - } - catch (Exception e) - { - Assert.True(false, $"Unable to parse request as json: {e.Message}"); - } - } - - private class FakeMessageHandler : HttpMessageHandler - { - public string requestBody; - - protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) - { - requestBody = await request.Content.ReadAsStringAsync(); - - var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK) - { - Content = new StringContent("{}") - }; - return response; - } - } - } -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/HttpResponseDeserializerTests.txt b/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/HttpResponseDeserializerTests.txt deleted file mode 100644 index e3d1c5c5933..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/HttpResponseDeserializerTests.txt +++ /dev/null @@ -1,189 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Threading.Tasks; -using Xunit; -using HotChocolate.Execution; -using HotChocolate.Stitching.Utilities; -using Snapshooter.Xunit; -using HotChocolate.Language; -using Snapshooter; -using System.Linq; -using HotChocolate.Stitching.Pipeline; -using Newtonsoft.Json.Linq; - -namespace HotChocolate.Stitching -{ - public class HttpResponseDeserializerTests - { - [InlineData("hello", "string")] - [InlineData(1.5, "flot")] - [InlineData(123, "int")] - [InlineData(true, "bool")] - [Theory] - public async Task DeserializeQueryResult(object value, string type) - { - // arrange - var qux = new OrderedDictionary { { "quux", value } }; - var baz = new OrderedDictionary { { "qux", qux } }; - var objectList = new List { baz }; - var scalarList = new List { value }; - - var result = QueryResultBuilder.New(); - var data = new OrderedDictionary(); - data["foo"] = objectList; - data["bar"] = scalarList; - data["baz"] = baz; - result.SetData(data); - - var stream = new MemoryStream(); - var serializer = new JsonQueryResultSerializer(); - await serializer.SerializeAsync(result.Create(), stream); - byte[] buffer = stream.ToArray(); - - var serializedResult = Utf8GraphQLRequestParser.ParseJson(buffer); - - // act - IReadOnlyQueryResult deserializedResult = - HttpResponseDeserializer.Deserialize( - (IReadOnlyDictionary)serializedResult); - - // assert - Snapshot.Match(deserializedResult, - "DeserializeQueryResult_" + type); - } - - [Fact] - public async Task DeserializeQueryResultWithExtensions() - { - // arrange - var qux = new OrderedDictionary { { "quux", 123 } }; - var baz = new OrderedDictionary { { "qux", qux } }; - var objectList = new List { baz }; - var scalarList = new List { 123 }; - - var result = QueryResultBuilder.New(); - - var data = new OrderedDictionary(); - data["foo"] = objectList; - data["bar"] = scalarList; - data["baz"] = baz; - result.SetData(data); - - var extensionData = new ExtensionData(); - extensionData["foo"] = objectList; - extensionData["bar"] = scalarList; - extensionData["baz"] = baz; - result.SetExtensions(extensionData); - - var stream = new MemoryStream(); - var serializer = new JsonQueryResultSerializer(); - await serializer.SerializeAsync(result.Create(), stream); - byte[] buffer = stream.ToArray(); - - var serializedResult = Utf8GraphQLRequestParser.ParseJson(buffer); - - // act - IReadOnlyQueryResult deserializedResult = - HttpResponseDeserializer.Deserialize( - (IReadOnlyDictionary)serializedResult); - - // assert - deserializedResult.MatchSnapshot(m => m.Ignore(c => c.Field("Extensions"))); - deserializedResult.Extensions.OrderBy(t => t.Key) - .MatchSnapshot(new SnapshotNameExtension("extensions")); - } - - [Fact] - public async Task DeserializeQueryResultWithErrors() - { - // arrange - var qux = new OrderedDictionary { { "quux", 123 } }; - var baz = new OrderedDictionary { { "qux", qux } }; - var objectList = new List { baz }; - var scalarList = new List { 123 }; - - var result = QueryResultBuilder.New(); - - var data = new OrderedDictionary(); - data["foo"] = objectList; - data["bar"] = scalarList; - data["baz"] = baz; - result.SetData(data); - - result.AddError(ErrorBuilder.New() - .SetMessage("foo") - .SetPath(Path.New("root").Append("child")) - .AddLocation(new Location(15, 16)) - .SetExtension("bar", "baz") - .Build()); - - result.AddError(ErrorBuilder.New() - .SetMessage("qux") - .SetExtension("bar", "baz") - .Build()); - - result.AddError(ErrorBuilder.New() - .SetMessage("quux") - .Build()); - - var stream = new MemoryStream(); - var serializer = new JsonQueryResultSerializer(); - await serializer.SerializeAsync(result.Create(), stream); - byte[] buffer = stream.ToArray(); - - var serializedResult = Utf8GraphQLRequestParser.ParseJson(buffer); - - // act - IReadOnlyQueryResult deserializedResult = - HttpResponseDeserializer.Deserialize( - (IReadOnlyDictionary)serializedResult); - - // assert - Snapshot.Match(deserializedResult); - } - - [Fact] - public async Task DeserializeQueryResultOnlyErrors() - { - // arrange - var qux = new OrderedDictionary { { "quux", 123 } }; - var baz = new OrderedDictionary { { "qux", qux } }; - var objectList = new List { baz }; - var scalarList = new List { 123 }; - - var result = QueryResultBuilder.New(); - - result.AddError(ErrorBuilder.New() - .SetMessage("foo") - .SetPath(Path.New("root").Append("child")) - .AddLocation(new Location(15, 16)) - .SetExtension("bar", "baz") - .Build()); - - result.AddError(ErrorBuilder.New() - .SetMessage("qux") - .SetExtension("bar", "baz") - .Build()); - - result.AddError(ErrorBuilder.New() - .SetMessage("quux") - .Build()); - - - var stream = new MemoryStream(); - var serializer = new JsonQueryResultSerializer(); - await serializer.SerializeAsync(result.Create(), stream); - byte[] buffer = stream.ToArray(); - - var serializedResult = Utf8GraphQLRequestParser.ParseJson(buffer); - - // act - IReadOnlyQueryResult deserializedResult = - HttpResponseDeserializer.Deserialize( - (IReadOnlyDictionary)serializedResult); - - // assert - Snapshot.Match(deserializedResult); - } - } -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/MergeQueryRewriterTests.txt b/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/MergeQueryRewriterTests.txt deleted file mode 100644 index eeaaf9a0146..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/MergeQueryRewriterTests.txt +++ /dev/null @@ -1,176 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using ChilliCream.Testing; -using HotChocolate.Language; -using HotChocolate.Stitching.Requests; -using HotChocolate.Stitching.Utilities; -using Snapshooter.Xunit; -using Xunit; - -namespace HotChocolate.Stitching -{ - public class MergeQueryRewriterTests - { - [Fact] - public void SimpleShortHandQuery() - { - // arrange - string query_a = "{ a { b } }"; - string query_b = "{ c { d } }"; - string query_c = "{ a { c } }"; - - // act - var rewriter = new MergeRequestRewriter(Array.Empty()); - rewriter.AddQuery(Utf8GraphQLParser.Parse(query_a), "_a", false); - rewriter.AddQuery(Utf8GraphQLParser.Parse(query_b), "_b", false); - rewriter.AddQuery(Utf8GraphQLParser.Parse(query_c), "_c", false); - DocumentNode document = rewriter.Merge(); - - // assert - QuerySyntaxSerializer.Serialize(document).MatchSnapshot(); - } - - [Fact] - public void QueryWithPrivateVariables() - { - // arrange - DocumentNode query_a = Utf8GraphQLParser.Parse( - FileResource.Open("StitchingQueryWithUnion.graphql")); - DocumentNode query_b = Utf8GraphQLParser.Parse( - FileResource.Open("StitchingQueryWithVariables.graphql")); - - // act - var rewriter = new MergeRequestRewriter(Array.Empty()); - rewriter.AddQuery(query_a, "_a", false); - rewriter.AddQuery(query_b, "_b", false); - DocumentNode document = rewriter.Merge(); - - // assert - QuerySyntaxSerializer.Serialize(document).MatchSnapshot(); - } - - [Fact] - public void QueryWithGlobalVariables() - { - // arrange - DocumentNode query_a = Utf8GraphQLParser.Parse( - FileResource.Open("MergeQueryWithVariable.graphql")); - DocumentNode query_b = Utf8GraphQLParser.Parse( - FileResource.Open("MergeQueryWithVariable.graphql")); - - // act - var rewriter = new MergeRequestRewriter( - new HashSet(new[] { "global" })); - rewriter.AddQuery(query_a, "_a", true); - rewriter.AddQuery(query_b, "_b", true); - DocumentNode document = rewriter.Merge(); - - // assert - QuerySyntaxSerializer.Serialize(document).MatchSnapshot(); - } - - [Fact] - public void AliasesMapIsCorrect() - { - // arrange - DocumentNode query_a = Utf8GraphQLParser.Parse( - FileResource.Open("MergeQueryWithVariable.graphql")); - DocumentNode query_b = Utf8GraphQLParser.Parse( - FileResource.Open("MergeQueryWithVariable.graphql")); - - // act - var rewriter = new MergeRequestRewriter(Array.Empty()); - IDictionary a = - rewriter.AddQuery(query_a, "_a", true); - IDictionary b = - rewriter.AddQuery(query_b, "_b", true); - - // assert - a.MatchSnapshot("AliasesMapIsCorrect_A"); - b.MatchSnapshot("AliasesMapIsCorrect_B"); - } - - - [Fact] - public void DocumentHasNoOperation() - { - // arrange - DocumentNode query = Utf8GraphQLParser.Parse( - "type Foo { s: String }"); - - // act - var rewriter = new MergeRequestRewriter(Array.Empty()); - Action action = () => rewriter.AddQuery(query, "_a", false); - - // assert - Assert.Equal("document", - Assert.Throws(action).ParamName); - } - - [Fact] - public void DocumentIsNull() - { - // arrange - DocumentNode query = Utf8GraphQLParser.Parse( - "type Foo { s: String }"); - - // act - var rewriter = new MergeRequestRewriter(Array.Empty()); - Action action = () => rewriter.AddQuery(null, "_a", false); - - // assert - Assert.Equal("document", - Assert.Throws(action).ParamName); - } - - [Fact] - public void QueriesAreNotOfTheSameOperationType() - { - // arrange - DocumentNode query_a = Utf8GraphQLParser.Parse("query a { b }"); - DocumentNode query_b = Utf8GraphQLParser.Parse("mutation a { b }"); - - // act - var rewriter = new MergeRequestRewriter(Array.Empty()); - rewriter.AddQuery(query_a, "abc", false); - Action action = () => rewriter.AddQuery(query_b, "abc", false); - - // assert - Assert.Equal("document", - Assert.Throws(action).ParamName); - } - - [Fact] - public void RequestPrefixIsEmpty() - { - // arrange - DocumentNode query = Utf8GraphQLParser.Parse( - "type Foo { s: String }"); - - // act - var rewriter = new MergeRequestRewriter(Array.Empty()); - Action action = () => rewriter.AddQuery( - query, default(NameString), false); - - // assert - Assert.Equal("requestPrefix", - Assert.Throws(action).ParamName); - } - - [Fact] - public void CreateNewInstance_GlobalVariablesIsNull() - { - // arrange - DocumentNode query = Utf8GraphQLParser.Parse( - "type Foo { s: String }"); - - // act - Action action = () => new MergeRequestRewriter(null); - - // assert - Assert.Equal("globalVariableNames", - Assert.Throws(action).ParamName); - } - } -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/AliasesMapIsCorrect_A.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/AliasesMapIsCorrect_A.snap deleted file mode 100644 index 174b4e078fd..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/AliasesMapIsCorrect_A.snap +++ /dev/null @@ -1,3 +0,0 @@ -{ - "_a_customer": "customer" -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/AliasesMapIsCorrect_B.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/AliasesMapIsCorrect_B.snap deleted file mode 100644 index 11fead6f8a2..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/AliasesMapIsCorrect_B.snap +++ /dev/null @@ -1,3 +0,0 @@ -{ - "_b_customer": "customer" -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/DeserializeQueryResult_bool.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/DeserializeQueryResult_bool.snap deleted file mode 100644 index 00a4d7baf5b..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/DeserializeQueryResult_bool.snap +++ /dev/null @@ -1,22 +0,0 @@ -{ - "Data": { - "foo": [ - { - "qux": { - "quux": true - } - } - ], - "bar": [ - true - ], - "baz": { - "qux": { - "quux": true - } - } - }, - "Errors": null, - "Extensions": null, - "ContextData": null -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/DeserializeQueryResult_flot.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/DeserializeQueryResult_flot.snap deleted file mode 100644 index e72b75008f4..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/DeserializeQueryResult_flot.snap +++ /dev/null @@ -1,22 +0,0 @@ -{ - "Data": { - "foo": [ - { - "qux": { - "quux": 1.5 - } - } - ], - "bar": [ - 1.5 - ], - "baz": { - "qux": { - "quux": 1.5 - } - } - }, - "Errors": null, - "Extensions": null, - "ContextData": null -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/DeserializeQueryResult_int.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/DeserializeQueryResult_int.snap deleted file mode 100644 index bdf57e3b573..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/DeserializeQueryResult_int.snap +++ /dev/null @@ -1,22 +0,0 @@ -{ - "Data": { - "foo": [ - { - "qux": { - "quux": 123 - } - } - ], - "bar": [ - 123 - ], - "baz": { - "qux": { - "quux": 123 - } - } - }, - "Errors": null, - "Extensions": null, - "ContextData": null -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/DeserializeQueryResult_string.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/DeserializeQueryResult_string.snap deleted file mode 100644 index 155596793b6..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/DeserializeQueryResult_string.snap +++ /dev/null @@ -1,22 +0,0 @@ -{ - "Data": { - "foo": [ - { - "qux": { - "quux": "hello" - } - } - ], - "bar": [ - "hello" - ], - "baz": { - "qux": { - "quux": "hello" - } - } - }, - "Errors": null, - "Extensions": null, - "ContextData": null -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractFieldWithDirective_Stitching.graphql_StitchingQueryWithSkip.graphql.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractFieldWithDirective_Stitching.graphql_StitchingQueryWithSkip.graphql.snap deleted file mode 100644 index 801c193e738..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractFieldWithDirective_Stitching.graphql_StitchingQueryWithSkip.graphql.snap +++ /dev/null @@ -1,11 +0,0 @@ -query fetch($skip: Boolean) { - customer(id: "Q3VzdG9tZXIKZDE=") { - name - consultant @skip(if: $skip) { - name - __typename - } - id - __typename - } -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_Stitching.graphql_StitchingQuery.graphql.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_Stitching.graphql_StitchingQuery.graphql.snap deleted file mode 100644 index 8cbdceec05e..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_Stitching.graphql_StitchingQuery.graphql.snap +++ /dev/null @@ -1,11 +0,0 @@ -query fetch { - customer(id: "Q3VzdG9tZXIKZDE=") { - name - consultant { - name - __typename - } - id - __typename - } -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_Stitching.graphql_StitchingQueryWithArguments.graphql.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_Stitching.graphql_StitchingQueryWithArguments.graphql.snap deleted file mode 100644 index 997bed459f8..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_Stitching.graphql_StitchingQueryWithArguments.graphql.snap +++ /dev/null @@ -1,6 +0,0 @@ -query fetch { - contracts(id: "Q3VzdG9tZXIKZDE=") { - id - __typename - } -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_Stitching.graphql_StitchingQueryWithFragmentDefs.graphql.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_Stitching.graphql_StitchingQueryWithFragmentDefs.graphql.snap deleted file mode 100644 index 8cbdceec05e..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_Stitching.graphql_StitchingQueryWithFragmentDefs.graphql.snap +++ /dev/null @@ -1,11 +0,0 @@ -query fetch { - customer(id: "Q3VzdG9tZXIKZDE=") { - name - consultant { - name - __typename - } - id - __typename - } -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_Stitching.graphql_StitchingQueryWithInlineFragment.graphql.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_Stitching.graphql_StitchingQueryWithInlineFragment.graphql.snap deleted file mode 100644 index 8cbdceec05e..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_Stitching.graphql_StitchingQueryWithInlineFragment.graphql.snap +++ /dev/null @@ -1,11 +0,0 @@ -query fetch { - customer(id: "Q3VzdG9tZXIKZDE=") { - name - consultant { - name - __typename - } - id - __typename - } -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_Stitching.graphql_StitchingQueryWithTypename.graphql.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_Stitching.graphql_StitchingQueryWithTypename.graphql.snap deleted file mode 100644 index f5f5f767a29..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_Stitching.graphql_StitchingQueryWithTypename.graphql.snap +++ /dev/null @@ -1,6 +0,0 @@ -query fetch { - consultant { - __typename - name - } -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_Stitching.graphql_StitchingQueryWithUnion.graphql.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_Stitching.graphql_StitchingQueryWithUnion.graphql.snap deleted file mode 100644 index f0b0cb18f65..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_Stitching.graphql_StitchingQueryWithUnion.graphql.snap +++ /dev/null @@ -1,26 +0,0 @@ -query fetch { - customer: customerOrConsultant(id: "Q3VzdG9tZXIKZDE=") { - ... customer - ... consultant - ... on Customer { - id - __typename - } - __typename - } -} - -fragment customer on Customer { - name - consultant { - name - __typename - } - id - __typename -} - -fragment consultant on Consultant { - name - __typename -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_Stitching.graphql_StitchingQueryWithVariables.graphql.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_Stitching.graphql_StitchingQueryWithVariables.graphql.snap deleted file mode 100644 index cf5543f9ae7..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_Stitching.graphql_StitchingQueryWithVariables.graphql.snap +++ /dev/null @@ -1,12 +0,0 @@ -query fetch($customerId: ID!, $deep: String!, $deeper: String!, $deeperInArray: String, $deeperArray: String, $complex: ComplexInputType) { - customer(id: $customerId) { - name - consultant { - name - __typename - } - complexArg(arg: { value: $deep, deeper: { value: "CONSTANT", deeper: { value: $deeper, deeperArray: [ { value: "CONSTANT_ARRAY", deeper: { value: $deeperInArray } } ] } }, deeperArray: [ { value: "CONSTANT_ARRAY", deeper: { value: $deeperArray } }, $complex ] }) - id - __typename - } -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_StitchingComputed.graphql_StitchingQueryComputedField.graphql.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_StitchingComputed.graphql_StitchingQueryComputedField.graphql.snap deleted file mode 100644 index c0119903839..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_StitchingComputed.graphql_StitchingQueryComputedField.graphql.snap +++ /dev/null @@ -1,7 +0,0 @@ -query fetch { - customer(id: "Q3VzdG9tZXIKZDE=") { - id - name - __typename - } -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_WithCustomRewriters.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_WithCustomRewriters.snap deleted file mode 100644 index 08f53415b52..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/ExtractFieldQuerySyntaxRewriterTests.ExtractField_WithCustomRewriters.snap +++ /dev/null @@ -1,13 +0,0 @@ -query fetch { - foo_bar: customer(id: "Q3VzdG9tZXIKZDE=") { - foo_bar: name - foo_bar: consultant { - foo_bar: name - foo_bar: __typename - abc_def - } - foo_bar: id - foo_bar: __typename - abc_def - } -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/FieldDependencyResolverTests.GetFieldDependencies.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/FieldDependencyResolverTests.GetFieldDependencies.snap deleted file mode 100644 index d736e4122ca..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/FieldDependencyResolverTests.GetFieldDependencies.snap +++ /dev/null @@ -1,6 +0,0 @@ -[ - { - "TypeName": "Customer", - "FieldName": "id" - } -] diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/HttpResponseDeserializerTests.DeserializeQueryResultOnlyErrors.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/HttpResponseDeserializerTests.DeserializeQueryResultOnlyErrors.snap deleted file mode 100644 index c41668a1263..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/HttpResponseDeserializerTests.DeserializeQueryResultOnlyErrors.snap +++ /dev/null @@ -1,43 +0,0 @@ -{ - "Data": {}, - "Errors": [ - { - "Message": "foo", - "Code": null, - "Path": [ - "root", - "child" - ], - "Locations": [ - { - "Line": 15, - "Column": 16 - } - ], - "Exception": null, - "Extensions": { - "bar": "baz" - } - }, - { - "Message": "qux", - "Code": null, - "Path": null, - "Locations": [], - "Exception": null, - "Extensions": { - "bar": "baz" - } - }, - { - "Message": "quux", - "Code": null, - "Path": null, - "Locations": [], - "Exception": null, - "Extensions": {} - } - ], - "Extensions": null, - "ContextData": null -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/HttpResponseDeserializerTests.DeserializeQueryResultWithErrors.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/HttpResponseDeserializerTests.DeserializeQueryResultWithErrors.snap deleted file mode 100644 index b2a9504597a..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/HttpResponseDeserializerTests.DeserializeQueryResultWithErrors.snap +++ /dev/null @@ -1,59 +0,0 @@ -{ - "Data": { - "foo": [ - { - "qux": { - "quux": 123 - } - } - ], - "bar": [ - 123 - ], - "baz": { - "qux": { - "quux": 123 - } - } - }, - "Errors": [ - { - "Message": "foo", - "Code": null, - "Path": [ - "root", - "child" - ], - "Locations": [ - { - "Line": 15, - "Column": 16 - } - ], - "Exception": null, - "Extensions": { - "bar": "baz" - } - }, - { - "Message": "qux", - "Code": null, - "Path": null, - "Locations": [], - "Exception": null, - "Extensions": { - "bar": "baz" - } - }, - { - "Message": "quux", - "Code": null, - "Path": null, - "Locations": [], - "Exception": null, - "Extensions": {} - } - ], - "Extensions": null, - "ContextData": null -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/HttpResponseDeserializerTests.DeserializeQueryResultWithExtensions.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/HttpResponseDeserializerTests.DeserializeQueryResultWithExtensions.snap deleted file mode 100644 index 6f30fbdc30e..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/HttpResponseDeserializerTests.DeserializeQueryResultWithExtensions.snap +++ /dev/null @@ -1,38 +0,0 @@ -{ - "Data": { - "foo": [ - { - "qux": { - "quux": 123 - } - } - ], - "bar": [ - 123 - ], - "baz": { - "qux": { - "quux": 123 - } - } - }, - "Errors": null, - "Extensions": { - "bar": [ - 123 - ], - "foo": [ - { - "qux": { - "quux": 123 - } - } - ], - "baz": { - "qux": { - "quux": 123 - } - } - }, - "ContextData": null -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/HttpResponseDeserializerTests.DeserializeQueryResultWithExtensions_extensions.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/HttpResponseDeserializerTests.DeserializeQueryResultWithExtensions_extensions.snap deleted file mode 100644 index 845dfef29dd..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/HttpResponseDeserializerTests.DeserializeQueryResultWithExtensions_extensions.snap +++ /dev/null @@ -1,26 +0,0 @@ -[ - { - "Key": "bar", - "Value": [ - 123 - ] - }, - { - "Key": "baz", - "Value": { - "qux": { - "quux": 123 - } - } - }, - { - "Key": "foo", - "Value": [ - { - "qux": { - "quux": 123 - } - } - ] - } -] diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/MergeQueryRewriterTests.QueryWithGlobalVariables.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/MergeQueryRewriterTests.QueryWithGlobalVariables.snap deleted file mode 100644 index beff3b069ca..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/MergeQueryRewriterTests.QueryWithGlobalVariables.snap +++ /dev/null @@ -1,32 +0,0 @@ -query exec_batch($_a_fields_customerId: ID!, $global: ID!, $_b_fields_customerId: ID!) { - _a_customer: customer(id: $_a_customerId) { - name - consultant(id: $global) { - name - } - contracts { - id - ... life - ... other - } - } - _b_customer: customer(id: $_b_customerId) { - name - consultant(id: $global) { - name - } - contracts { - id - ... life - ... other - } - } -} - -fragment life on LifeInsuranceContract { - premium -} - -fragment other on SomeOtherContract { - expiryDate -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/MergeQueryRewriterTests.QueryWithPrivateVariables.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/MergeQueryRewriterTests.QueryWithPrivateVariables.snap deleted file mode 100644 index c47832409c0..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/MergeQueryRewriterTests.QueryWithPrivateVariables.snap +++ /dev/null @@ -1,46 +0,0 @@ -query exec_batch($_b_customerId: ID!, $_b_deep: String!, $_b_deeper: String!, $_b_deeperArray: String, $_b_complex: ComplexInputType, $_b_deeperInArray: String) { - _a_customer: customerOrConsultant(id: "Q3VzdG9tZXIKZDE=") { - ... _a_customer - ... _a_consultant - } - _a_consultant: customerOrConsultant(id: "Q29uc3VsdGFudApkMQ==") { - ... _a_customer - ... _a_consultant - } - _b_customer: customer(id: $_b_customerId) { - name - consultant { - name - } - complexArg(arg: { value: $_b_deep, deeper: { value: "CONSTANT", deeper: { value: $_b_deeper, deeperArray: [ { value: "CONSTANT_ARRAY", deeper: { value: $_b_deeperInArray } } ] } }, deeperArray: [ { value: "CONSTANT_ARRAY", deeper: { value: $_b_deeperArray } }, $_b_complex ] }) - contracts { - id - ... on LifeInsuranceContract { - premium - } - ... on SomeOtherContract { - expiryDate - } - } - } -} - -fragment _a_customer on Customer { - name - consultant { - name - } - contracts { - id - ... on LifeInsuranceContract { - premium - } - ... on SomeOtherContract { - expiryDate - } - } -} - -fragment _a_consultant on Consultant { - name -} diff --git a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/MergeQueryRewriterTests.SimpleShortHandQuery.snap b/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/MergeQueryRewriterTests.SimpleShortHandQuery.snap deleted file mode 100644 index c3721b42639..00000000000 --- a/src/HotChocolate/Stitching/test/Stitching.Tests/Utilities/__snapshots__/MergeQueryRewriterTests.SimpleShortHandQuery.snap +++ /dev/null @@ -1,11 +0,0 @@ -query exec_batch { - _a_a: a { - b - } - _b_c: c { - d - } - _c_a: a { - c - } -}