From 60d9edbae520cc0a40fcbe1e91fddb7c3ed4b62f Mon Sep 17 00:00:00 2001 From: Kevin Carroll Date: Sun, 7 Jul 2024 13:48:30 -0700 Subject: [PATCH 1/7] Editable Graph Message Properties (#161) * Fixed a bug to apply the correct default error code on `GraphExecutionMessage` when its not provided * Updated `IGraphMessage` and its implementations to allow allow for editing of `Code`, `Message` and `Exception` properties. * Added unit tests to ensure the above * Removed `.NET 7` build targets since it has reached end of life. --- .github/workflows/ci-build.yml | 1 - .github/workflows/nuget-deployment.yml | 1 - .../starwars/starwars-api70/Program.cs | 29 --- .../Properties/launchSettings.json | 12 -- .../starwars/starwars-api70/Startup.cs | 174 ------------------ .../starwars/starwars-api70/appsettings.json | 12 -- .../starwars-api70/starwars-api70.csproj | 26 --- src/graphql-aspnet.sln | 7 - .../Execution/DirectiveProcessorTypeSystem.cs | 2 +- .../Execution/GraphExecutionMessage.cs | 62 +++---- .../Execution/GraphMessageCollection.cs | 6 +- .../Interfaces/Execution/IGraphMessage.cs | 25 ++- .../Execution/IGraphMessageCollection.cs | 6 +- src/library-common.props | 2 +- src/library-tests.props | 2 +- .../Schemas/GraphExecutionMessageTests.cs | 88 +++++++++ 16 files changed, 138 insertions(+), 317 deletions(-) delete mode 100644 src/ancillary-projects/starwars/starwars-api70/Program.cs delete mode 100644 src/ancillary-projects/starwars/starwars-api70/Properties/launchSettings.json delete mode 100644 src/ancillary-projects/starwars/starwars-api70/Startup.cs delete mode 100644 src/ancillary-projects/starwars/starwars-api70/appsettings.json delete mode 100644 src/ancillary-projects/starwars/starwars-api70/starwars-api70.csproj create mode 100644 src/unit-tests/graphql-aspnet-tests/Schemas/GraphExecutionMessageTests.cs diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index 4ff3960d3..14e8de546 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -38,7 +38,6 @@ jobs: with: dotnet-version: | 6.x - 7.x 8.x # --------------------------------------- diff --git a/.github/workflows/nuget-deployment.yml b/.github/workflows/nuget-deployment.yml index 7b518cd86..99957abba 100644 --- a/.github/workflows/nuget-deployment.yml +++ b/.github/workflows/nuget-deployment.yml @@ -40,7 +40,6 @@ jobs: with: dotnet-version: | 6.x - 7.x 8.x # --------------------------------------- diff --git a/src/ancillary-projects/starwars/starwars-api70/Program.cs b/src/ancillary-projects/starwars/starwars-api70/Program.cs deleted file mode 100644 index ddd499734..000000000 --- a/src/ancillary-projects/starwars/starwars-api70/Program.cs +++ /dev/null @@ -1,29 +0,0 @@ -// ************************************************************* -// project: graphql-aspnet -// -- -// repo: https://github.com/graphql-aspnet -// docs: https://graphql-aspnet.github.io -// -- -// License: MIT -// ************************************************************* - -namespace GraphQL.AspNet.StarWarsAPI7X -{ - using Microsoft.AspNetCore.Hosting; - using Microsoft.Extensions.Hosting; - - public static class Program - { - public static void Main(string[] args) - { - CreateHostBuilder(args).Build().Run(); - } - - public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseStartup(); - }); - } -} \ No newline at end of file diff --git a/src/ancillary-projects/starwars/starwars-api70/Properties/launchSettings.json b/src/ancillary-projects/starwars/starwars-api70/Properties/launchSettings.json deleted file mode 100644 index 530c470fd..000000000 --- a/src/ancillary-projects/starwars/starwars-api70/Properties/launchSettings.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "$schema": "http://json.schemastore.org/launchsettings.json", - "profiles": { - "StarWars: .NET 7": { - "commandName": "Project", - "applicationUrl": "http://localhost:5000", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - } - } -} diff --git a/src/ancillary-projects/starwars/starwars-api70/Startup.cs b/src/ancillary-projects/starwars/starwars-api70/Startup.cs deleted file mode 100644 index 623c735d9..000000000 --- a/src/ancillary-projects/starwars/starwars-api70/Startup.cs +++ /dev/null @@ -1,174 +0,0 @@ -// ************************************************************* -// project: graphql-aspnet -// -- -// repo: https://github.com/graphql-aspnet -// docs: https://graphql-aspnet.github.io -// -- -// License: MIT -// ************************************************************* - -namespace GraphQL.AspNet.StarWarsAPI7X -{ - using System; - using GraphQL.AspNet; - using GraphQL.AspNet.Configuration; - using GraphQL.AspNet.Execution; - using GraphQL.AspNet.StarwarsAPI.Common.Services; - using Microsoft.AspNetCore.Builder; - using Microsoft.AspNetCore.Hosting; - using Microsoft.AspNetCore.WebSockets; - using Microsoft.Extensions.Configuration; - using Microsoft.Extensions.DependencyInjection; - - public class Startup - { - private const string ALL_ORIGINS_POLICY = "_allOrigins"; - - private static readonly TimeSpan SOCKET_CONNECTION_KEEPALIVE = TimeSpan.FromSeconds(10); - - /// - /// Initializes a new instance of the class. - /// - /// The configuration created to govern the - /// application environment. - public Startup(IConfiguration configuration) - { - this.Configuration = configuration; - } - - /// - /// Configures the service collection to be built for this application instance. - /// - /// The services. - public void ConfigureServices(IServiceCollection services) - { - services.AddSingleton(); - services.AddScoped(); - - // apply an unrestricted cors policy for the demo services - // to allow use on many of the tools for testing (graphiql, altair etc.) - // Do not do this in production - services.AddCors(options => - { - options.AddPolicy( - ALL_ORIGINS_POLICY, - builder => - { - builder.AllowAnyOrigin() - .AllowAnyHeader() - .AllowAnyMethod(); - }); - }); - - // ASP.NET websockets implementation must also be added to the runtime - services.AddWebSockets((options) => - { - // here add some common origins of various tools that may be - // used for running this demo - // do not add these in a production app unless you need - // to - options.AllowedOrigins.Add("http://localhost:5000"); - options.AllowedOrigins.Add("http://localhost:4000"); - options.AllowedOrigins.Add("http://localhost:3000"); - options.AllowedOrigins.Add("null"); - options.AllowedOrigins.Add("file://"); - options.AllowedOrigins.Add("ws://"); - - }); - - // ---------------------------------------------------------- - // Register GraphQL with the application - // ---------------------------------------------------------- - // By default graphql will scan your assembly for any GraphControllers - // and automatically wire them up to the schema - // you can control which assemblies are scanned and which classes are registered using - // the schema configuration options set here. - // - // in this example because of the two test projects (netcore3.1 and net5.0) - // we have moved all the shared code to a common assembly (starwars-common) and are injecting it - // as a single unit - // - // we then add subscription services to the schema builder returned from .AddGraphQL() - services.AddGraphQL(options => - { - options.ResponseOptions.ExposeExceptions = true; - options.ResponseOptions.MessageSeverityLevel = GraphMessageSeverity.Information; - - // options.ExecutionOptions.EnableMetrics = true; - // options.ResponseOptions.ExposeMetrics = true; - - var assembly = typeof(StarWarsDataRepository).Assembly; - options.AddAssembly(assembly); - }) - .AddSubscriptions(options => - { - // this route path is set by default - // it is listed here just as a matter of example - options.Route = SubscriptionConstants.Routing.DEFAULT_SUBSCRIPTIONS_ROUTE; - - // for some web based graphql tools such as graphiql and graphql-playground - // the default keep-alive timeout of 2 minutes is too long. - // - // still others (like graphql-playground running in electron) do not respond/configure - // for socket-level ping/pong frames to allow for socket-level keep alives - // - // here we set this demo project websocket keep-alive (at the server level) - // to be below all those thresholds to ensure a hassle free experience. - // In practice, you should configure your server (both subscription keep alives and socket keep alives) - // with an interval that is compatiable with your client side environment. - options.ConnectionKeepAliveInterval = SOCKET_CONNECTION_KEEPALIVE; - }); - - // if you have rest controllers this item be sure they are included. - // Graphql and rest can live side by side in the same project without issue - // -------------------------------------------------- - // builder.Services.AddControllers(); - } - - /// - /// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - /// - /// The asp.net application builder. - /// The configured host environment. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - app.AddStarWarsStartedMessageToConsole(); - - app.UseRouting(); - - app.UseCors(ALL_ORIGINS_POLICY); - - app.UseAuthorization(); - - // enable web sockets on this server instance - // this must be done before a call to 'UseGraphQL' if subscriptions are enabled for any - // schema otherwise the subscriptions may not register correctly - app.UseWebSockets(); - - // if you have no rest controllers this item can be safely skipped - // graphql and rest can live side by side in the same project without issue - // app.UseEndpoints(endpoints => - // { - // endpoints.MapControllers(); - // }); - - // ************************************************************ - // Finalize the graphql setup: - // 1) Loading the schema - // 2) Publish the route to hook the graphql runtime to ASP.NET. - // - // Be sure to register it after "UseAuthorization" if you need it. - // - // If the construction of your runtime schema has any errors they will be thrown here - // before your application starts listening for requests. - // ************************************************************ - app.UseGraphQL(); - } - - /// - /// Gets the environment configuration for this instance. - /// - /// The configuration item. - public IConfiguration Configuration { get; } - } -} \ No newline at end of file diff --git a/src/ancillary-projects/starwars/starwars-api70/appsettings.json b/src/ancillary-projects/starwars/starwars-api70/appsettings.json deleted file mode 100644 index 289add7ec..000000000 --- a/src/ancillary-projects/starwars/starwars-api70/appsettings.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft": "Information", - "Microsoft.AspNetCore.Hosting.Internal.WebHost": "Debug", - "Microsoft.AspNetCore.Hosting.Diagnostics": "Debug", - "GraphQL.AspNet": "Warning" - } - }, - "AllowedHosts": "*" -} diff --git a/src/ancillary-projects/starwars/starwars-api70/starwars-api70.csproj b/src/ancillary-projects/starwars/starwars-api70/starwars-api70.csproj deleted file mode 100644 index a9df881c7..000000000 --- a/src/ancillary-projects/starwars/starwars-api70/starwars-api70.csproj +++ /dev/null @@ -1,26 +0,0 @@ - - - - net7.0 - latest - $(NoWarn);1701;1702;1705;1591;NU1603 - GraphQL.AspNet.StarWarsAPI7X - GraphQL.AspNet.StarwarsAPI7X - true - - - - ..\..\..\styles.ruleset - - - - - - - - - - - - - diff --git a/src/graphql-aspnet.sln b/src/graphql-aspnet.sln index b796713d9..f3978b89f 100644 --- a/src/graphql-aspnet.sln +++ b/src/graphql-aspnet.sln @@ -31,8 +31,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "graphql-aspnet-subscription EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "graphql-aspnet-subscriptions-tests", "unit-tests\graphql-aspnet-subscriptions-tests\graphql-aspnet-subscriptions-tests.csproj", "{6E4A16F5-1B98-412E-9A88-F56301F5D0E4}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "starwars-api70", "ancillary-projects\starwars\starwars-api70\starwars-api70.csproj", "{B92A5C91-F88D-4F26-8775-20C72692BD43}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "graphql-aspnet-tests-common", "unit-tests\graphql-aspnet-tests-common\graphql-aspnet-tests-common.csproj", "{3CB086E3-5E7B-438B-9A95-AEA264009521}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "starwars-api80", "ancillary-projects\starwars\starwars-api80\starwars-api80.csproj", "{43C9EB6E-5FFE-4EC6-B21B-09C715B7B114}" @@ -70,10 +68,6 @@ Global {6E4A16F5-1B98-412E-9A88-F56301F5D0E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6E4A16F5-1B98-412E-9A88-F56301F5D0E4}.Debug|Any CPU.Build.0 = Debug|Any CPU {6E4A16F5-1B98-412E-9A88-F56301F5D0E4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B92A5C91-F88D-4F26-8775-20C72692BD43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B92A5C91-F88D-4F26-8775-20C72692BD43}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B92A5C91-F88D-4F26-8775-20C72692BD43}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B92A5C91-F88D-4F26-8775-20C72692BD43}.Release|Any CPU.Build.0 = Release|Any CPU {3CB086E3-5E7B-438B-9A95-AEA264009521}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3CB086E3-5E7B-438B-9A95-AEA264009521}.Debug|Any CPU.Build.0 = Debug|Any CPU {3CB086E3-5E7B-438B-9A95-AEA264009521}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -96,7 +90,6 @@ Global {5F6EBAF4-B5EB-4DBD-8F51-17BBC2E8984D} = {22C7BC5B-EC8E-4A07-9968-961E86AB44E2} {5DE081AA-494A-4377-B2CA-6952715D513D} = {350D3594-5D97-4D9B-A01D-D3A5C036318C} {6E4A16F5-1B98-412E-9A88-F56301F5D0E4} = {350D3594-5D97-4D9B-A01D-D3A5C036318C} - {B92A5C91-F88D-4F26-8775-20C72692BD43} = {22C7BC5B-EC8E-4A07-9968-961E86AB44E2} {3CB086E3-5E7B-438B-9A95-AEA264009521} = {350D3594-5D97-4D9B-A01D-D3A5C036318C} {43C9EB6E-5FFE-4EC6-B21B-09C715B7B114} = {22C7BC5B-EC8E-4A07-9968-961E86AB44E2} {E67D4FB2-73FF-4EC1-80F8-5D4DEC57F5AA} = {350D3594-5D97-4D9B-A01D-D3A5C036318C} diff --git a/src/graphql-aspnet/Execution/DirectiveProcessorTypeSystem.cs b/src/graphql-aspnet/Execution/DirectiveProcessorTypeSystem.cs index 349c7b488..ef745eb78 100644 --- a/src/graphql-aspnet/Execution/DirectiveProcessorTypeSystem.cs +++ b/src/graphql-aspnet/Execution/DirectiveProcessorTypeSystem.cs @@ -15,12 +15,12 @@ namespace GraphQL.AspNet.Execution using System.Threading; using GraphQL.AspNet.Common; using GraphQL.AspNet.Common.Extensions; - using GraphQL.AspNet.Execution.Source; using GraphQL.AspNet.Configuration.Exceptions; using GraphQL.AspNet.Directives; using GraphQL.AspNet.Execution.Contexts; using GraphQL.AspNet.Execution.Exceptions; using GraphQL.AspNet.Execution.QueryPlans.InputArguments; + using GraphQL.AspNet.Execution.Source; using GraphQL.AspNet.Interfaces.Execution; using GraphQL.AspNet.Interfaces.Execution.QueryPlans.InputArguments; using GraphQL.AspNet.Interfaces.Logging; diff --git a/src/graphql-aspnet/Execution/GraphExecutionMessage.cs b/src/graphql-aspnet/Execution/GraphExecutionMessage.cs index 92773d8fa..2b89b1bba 100644 --- a/src/graphql-aspnet/Execution/GraphExecutionMessage.cs +++ b/src/graphql-aspnet/Execution/GraphExecutionMessage.cs @@ -13,8 +13,8 @@ namespace GraphQL.AspNet.Execution using System.Collections.Generic; using System.Diagnostics; using GraphQL.AspNet.Execution.Source; - using GraphQL.AspNet.Interfaces.Execution.RulesEngine; using GraphQL.AspNet.Interfaces.Execution; + using GraphQL.AspNet.Interfaces.Execution.RulesEngine; /// /// A default, concrete implementation of a used @@ -76,6 +76,9 @@ internal static IGraphMessage FromValidationRule( return graphMessage; } + private string _message; + private string _code; + /// /// Initializes a new instance of the class. /// @@ -92,58 +95,41 @@ public GraphExecutionMessage( Exception exception = null) { this.Origin = origin; - this.Code = code?.Trim() ?? "-unknown-"; - this.Message = message?.Trim(); + this.Code = code; + this.Message = message; this.Severity = severity; this.Exception = exception; this.TimeStamp = DateTimeOffset.UtcNow; this.MetaData = new Dictionary(); } - /// - /// Gets the time stamp when this message was created. - /// - /// The time stamp. + /// public DateTimeOffset TimeStamp { get; } - /// - /// Gets the origin in the provided source text, if any, this message relates to. - /// This value is returned as part of a query response. - /// - /// The location. + /// public SourceOrigin Origin { get; } - /// - /// Gets an error code identifying this error. This value is returned as part of a query response. - /// - /// The code. - public string Code { get; } + /// + public string Code + { + get => _code; + set => _code = value?.Trim() ?? Constants.ErrorCodes.DEFAULT; + } - /// - /// Gets a human-friendly message that conveys details about the error tht occured. This value is - /// returned as part of a query response. - /// - /// The message. - public string Message { get; } + /// + public string Message + { + get => _message; + set => _message = value?.Trim(); + } - /// - /// Gets an (optional) exception that may have occured to generate the error. The exception - /// is only conveyed to the requestor if the request is configured to expose exceptions. - /// - /// The exception. - public Exception Exception { get; } + /// + public Exception Exception { get; set; } - /// - /// Gets the severity of this message that was generated. - /// - /// The severity. + /// public GraphMessageSeverity Severity { get; } - /// - /// Gets additional metadata defined for this message. This data will be added as key/value pairs - /// when the message is rendered to an graph output. - /// - /// The meta data. + /// public IDictionary MetaData { get; } } } \ No newline at end of file diff --git a/src/graphql-aspnet/Execution/GraphMessageCollection.cs b/src/graphql-aspnet/Execution/GraphMessageCollection.cs index 844f747f2..6632dbc16 100644 --- a/src/graphql-aspnet/Execution/GraphMessageCollection.cs +++ b/src/graphql-aspnet/Execution/GraphMessageCollection.cs @@ -16,11 +16,7 @@ namespace GraphQL.AspNet.Execution using GraphQL.AspNet.Execution.Source; using GraphQL.AspNet.Interfaces.Execution; - /// - /// A collection of messages produced while completing a requested graph operation. Messages generated - /// by the runtime or by custom code on field requests are aggregated and inspected for severity levels to - /// deteremine if processing should cease or when a response needs to be sent to the requestor. - /// + /// [DebuggerDisplay("Count = {Count}, Severity = {Severity}")] [DebuggerTypeProxy(typeof(GraphMessageCollectionDebugProxy))] [DebuggerStepThrough] diff --git a/src/graphql-aspnet/Interfaces/Execution/IGraphMessage.cs b/src/graphql-aspnet/Interfaces/Execution/IGraphMessage.cs index f0eb91f68..6bfa95069 100644 --- a/src/graphql-aspnet/Interfaces/Execution/IGraphMessage.cs +++ b/src/graphql-aspnet/Interfaces/Execution/IGraphMessage.cs @@ -11,8 +11,8 @@ namespace GraphQL.AspNet.Interfaces.Execution { using System; using System.Collections.Generic; - using GraphQL.AspNet.Execution.Source; using GraphQL.AspNet.Execution; + using GraphQL.AspNet.Execution.Source; /// /// An error of some kind that occured during the resolution of any graph item. @@ -22,6 +22,9 @@ public interface IGraphMessage /// /// Gets the time stamp (in UTC-0) when this message was created. /// + /// + /// This value is immutable once the message is created. + /// /// The time stamp. DateTimeOffset TimeStamp { get; } @@ -29,32 +32,38 @@ public interface IGraphMessage /// Gets the origin in the provided source text, if any, this message relates to. /// This value is returned as part of a query response. /// + /// + /// This value is immutable once the message is created. + /// /// The location. SourceOrigin Origin { get; } /// - /// Gets an error code identifying this error. This value is returned as part of a query response. + /// Gets or sets a standardized error code identifying this error. This value is returned as part of a query response. /// /// The code that can idenify this message or message type to a user. - string Code { get; } + string Code { get; set; } /// - /// Gets a human-friendly message that conveys details about the error tht occured. This value is + /// Gets or sets a human-friendly message that conveys details about the error tht occured. This value is /// returned as part of a query response. /// - /// The message. - string Message { get; } + /// The message contents. + string Message { get; set; } /// - /// Gets an (optional) exception that may have occured to generate the error. The exception + /// Gets or sets an (optional) exception that may have occured to generate the error. The exception /// is only conveyed to the requestor if the request is configured to expose exceptions. /// /// The exception that was originally thrown. - Exception Exception { get; } + Exception Exception { get; set; } /// /// Gets the severity of this message that was generated. /// + /// + /// This value is immutable once the message is created. + /// /// The severity of the message. GraphMessageSeverity Severity { get; } diff --git a/src/graphql-aspnet/Interfaces/Execution/IGraphMessageCollection.cs b/src/graphql-aspnet/Interfaces/Execution/IGraphMessageCollection.cs index 4c48f855e..fd21c1e1c 100644 --- a/src/graphql-aspnet/Interfaces/Execution/IGraphMessageCollection.cs +++ b/src/graphql-aspnet/Interfaces/Execution/IGraphMessageCollection.cs @@ -11,14 +11,18 @@ namespace GraphQL.AspNet.Interfaces.Execution { using System; using System.Collections.Generic; - using GraphQL.AspNet.Execution.Source; using GraphQL.AspNet.Execution; + using GraphQL.AspNet.Execution.Source; /// /// A collection of messages produced while completing a requested graph operation. Messages generated /// by the runtime or by custom code on field requests are aggregated and inspected for severity levels to /// deteremine if processing should cease or when a response needs to be sent to the request. /// + /// + /// Once added, the core identity of a message (e.g. , etc.) cannot be changed. + /// However, user facing values such as the or can be updated at will. + /// public interface IGraphMessageCollection : IReadOnlyList { /// diff --git a/src/library-common.props b/src/library-common.props index 1f5fff554..a58b2e858 100644 --- a/src/library-common.props +++ b/src/library-common.props @@ -1,7 +1,7 @@ - net8.0;net7.0;net6.0;netstandard2.0; + net8.0;net6.0;netstandard2.0; latest $(NoWarn);1701;1702;1705;1591;NU1603;IDE0019;IDE0017;RCS1146;RCS1194; diff --git a/src/library-tests.props b/src/library-tests.props index 37541a616..5d3fee9ea 100644 --- a/src/library-tests.props +++ b/src/library-tests.props @@ -1,7 +1,7 @@ - net8.0;net7.0;net6.0; + net8.0;net6.0; latest $(NoWarn);1701;1702;1705;1591;NU1603;IDE0019;IDE0017;RCS1146;RCS1194; GraphQL.AspNet.Tests diff --git a/src/unit-tests/graphql-aspnet-tests/Schemas/GraphExecutionMessageTests.cs b/src/unit-tests/graphql-aspnet-tests/Schemas/GraphExecutionMessageTests.cs new file mode 100644 index 000000000..fd91e6a1d --- /dev/null +++ b/src/unit-tests/graphql-aspnet-tests/Schemas/GraphExecutionMessageTests.cs @@ -0,0 +1,88 @@ +// ************************************************************* +// project: graphql-aspnet +// -- +// repo: https://github.com/graphql-aspnet +// docs: https://graphql-aspnet.github.io +// -- +// License: MIT +// ************************************************************* + +namespace GraphQL.AspNet.Tests.Schemas +{ + using GraphQL.AspNet.Execution; + using NUnit.Framework; + + [TestFixture] + public class GraphExecutionMessageTests + { + [TestCase("BOB", "BOB", "JOE", "JOE")] + [TestCase("", "", "", "")] + [TestCase(" ", "", " ", "")] + [TestCase(null, Constants.ErrorCodes.DEFAULT, null, Constants.ErrorCodes.DEFAULT)] + [TestCase(null, Constants.ErrorCodes.DEFAULT, "custom code ", "custom code")] + public void CodeTests(string initialValue, string expectedValue, string updatedValue, string expectedUpdatedValue) + { + var message = new GraphExecutionMessage(GraphMessageSeverity.Critical, "message", code: initialValue); + Assert.AreEqual(expectedValue, message.Code); + + message.Code = updatedValue; + Assert.AreEqual(expectedUpdatedValue, message.Code); + } + + [TestCase("BOB", "BOB", "JOIE", "JOIE")] + [TestCase("", "", "", "")] + [TestCase(" ", "", " ", "")] + [TestCase(null, null, "jane ", "jane")] + public void MessageTests(string initialValue, string expectedValue, string updatedValue, string expectedUpdatedValue) + { + var message = new GraphExecutionMessage(GraphMessageSeverity.Critical, message: initialValue); + Assert.AreEqual(expectedValue, message.Message); + + message.Message = updatedValue; + Assert.AreEqual(expectedUpdatedValue, message.Message); + } + + [Test] + public void ExceptionTest() + { + var ex = new System.Exception("test"); + var message = new GraphExecutionMessage( + GraphMessageSeverity.Critical, + message: "message", + exception: ex); + + Assert.AreEqual(ex, message.Exception); + } + + [Test] + public void ExceptionTest_WithRemoval() + { + var ex = new System.Exception("test"); + var message = new GraphExecutionMessage( + GraphMessageSeverity.Critical, + message: "message", + exception: ex); + + Assert.AreEqual(ex, message.Exception); + + message.Exception = null; + Assert.IsNull(message.Exception); + } + + [Test] + public void ExceptionTest_WithReplacement() + { + var ex = new System.Exception("test"); + var message = new GraphExecutionMessage( + GraphMessageSeverity.Critical, + message: "message", + exception: ex); + + Assert.AreEqual(ex, message.Exception); + + var ex2 = new System.Exception("test again"); + message.Exception = ex2; + Assert.AreEqual(ex2, message.Exception); + } + } +} From 8e827d86889490dc8bc21486db2e093efd8aa1e0 Mon Sep 17 00:00:00 2001 From: Kevin Carroll Date: Sun, 7 Jul 2024 13:49:37 -0700 Subject: [PATCH 2/7] Update README.md * removed .net 7 from readme text --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c24ef0558..c29109c62 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ### Documentation: [https://graphql-aspnet.github.io](https://graphql-aspnet.github.io) -> Targets: **netstandard2.0, net6.0, net7.0, net8.0** +> Targets: **netstandard2.0, net6.0, net8.0** [![CI-CD](https://github.com/graphql-aspnet/graphql-aspnet/actions/workflows/ci-build.yml/badge.svg?branch=master)](https://github.com/graphql-aspnet/graphql-aspnet/actions/workflows/ci-build.yml) From 536e4058ff68f18ba52e8bf8b1c48c09b3bed342 Mon Sep 17 00:00:00 2001 From: Kevin Carroll Date: Tue, 9 Jul 2024 15:51:20 -0700 Subject: [PATCH 3/7] Bump STJ (#162) --- src/library-common.props | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/library-common.props b/src/library-common.props index a58b2e858..8b9ae460e 100644 --- a/src/library-common.props +++ b/src/library-common.props @@ -55,10 +55,10 @@ - + - + @@ -68,7 +68,7 @@ - + From abbf21ef713b69de539d10501555e976a2e3d36c Mon Sep 17 00:00:00 2001 From: Kevin Carroll Date: Mon, 21 Oct 2024 07:11:09 -0700 Subject: [PATCH 4/7] Bumped STJ (#164) * Bumped referenced version of STJ from 8.0.4 to 8.0.5 --- src/library-common.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library-common.props b/src/library-common.props index 8b9ae460e..eacbad505 100644 --- a/src/library-common.props +++ b/src/library-common.props @@ -55,7 +55,7 @@ - + From 56d66fd11736df6f5075b0313a5d396d5265de3a Mon Sep 17 00:00:00 2001 From: Kevin Carroll Date: Tue, 21 Jan 2025 18:20:34 -0700 Subject: [PATCH 5/7] Updates for .NET 9 build targets (#166) * Removed .NET 6 build targets and unit tests * Added .NET 9 build targets and unit tests * Updated star wars API to target .NET 9 --- .github/workflows/ci-build.yml | 2 +- .github/workflows/nuget-deployment.yml | 2 +- .../Program.cs | 0 .../Properties/launchSettings.json | 0 .../appsettings.json | 0 .../starwars-api90.csproj} | 2 +- .../starwars-common/starwars-common.csproj | 2 +- .../WebSockets/WebSocketClientConnection.cs | 2 +- src/graphql-aspnet.sln | 14 ++++---- src/graphql-aspnet.sln.DotSettings | 9 ++++- .../DocumentNamedFragmentCollection.cs | 7 ++-- .../Execution/Response/ResponseFieldSet.cs | 7 ++-- .../GraphFieldArgumentCollection.cs | 7 ++-- .../Introspection/Model/IntrospectedSchema.cs | 9 ++--- src/library-common.props | 2 +- src/library-tests.props | 2 +- .../graphql-aspnet-testframework.csproj | 2 +- .../graphql-aspnet-tests-thirdpartydll.csproj | 2 +- .../Common/OrderedDictionaryTests.cs | 34 ++++++++++--------- 19 files changed, 59 insertions(+), 46 deletions(-) rename src/ancillary-projects/starwars/{starwars-api80 => starwars-api90}/Program.cs (100%) rename src/ancillary-projects/starwars/{starwars-api80 => starwars-api90}/Properties/launchSettings.json (100%) rename src/ancillary-projects/starwars/{starwars-api80 => starwars-api90}/appsettings.json (100%) rename src/ancillary-projects/starwars/{starwars-api80/starwars-api80.csproj => starwars-api90/starwars-api90.csproj} (94%) diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index 14e8de546..da3496987 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -37,8 +37,8 @@ jobs: name: Install .NET with: dotnet-version: | - 6.x 8.x + 9.x # --------------------------------------- # Configure the build environment diff --git a/.github/workflows/nuget-deployment.yml b/.github/workflows/nuget-deployment.yml index 99957abba..d9be6e265 100644 --- a/.github/workflows/nuget-deployment.yml +++ b/.github/workflows/nuget-deployment.yml @@ -39,8 +39,8 @@ jobs: name: Install .NET with: dotnet-version: | - 6.x 8.x + 9.x # --------------------------------------- # Configure the build environment diff --git a/src/ancillary-projects/starwars/starwars-api80/Program.cs b/src/ancillary-projects/starwars/starwars-api90/Program.cs similarity index 100% rename from src/ancillary-projects/starwars/starwars-api80/Program.cs rename to src/ancillary-projects/starwars/starwars-api90/Program.cs diff --git a/src/ancillary-projects/starwars/starwars-api80/Properties/launchSettings.json b/src/ancillary-projects/starwars/starwars-api90/Properties/launchSettings.json similarity index 100% rename from src/ancillary-projects/starwars/starwars-api80/Properties/launchSettings.json rename to src/ancillary-projects/starwars/starwars-api90/Properties/launchSettings.json diff --git a/src/ancillary-projects/starwars/starwars-api80/appsettings.json b/src/ancillary-projects/starwars/starwars-api90/appsettings.json similarity index 100% rename from src/ancillary-projects/starwars/starwars-api80/appsettings.json rename to src/ancillary-projects/starwars/starwars-api90/appsettings.json diff --git a/src/ancillary-projects/starwars/starwars-api80/starwars-api80.csproj b/src/ancillary-projects/starwars/starwars-api90/starwars-api90.csproj similarity index 94% rename from src/ancillary-projects/starwars/starwars-api80/starwars-api80.csproj rename to src/ancillary-projects/starwars/starwars-api90/starwars-api90.csproj index 39caf611a..44771342b 100644 --- a/src/ancillary-projects/starwars/starwars-api80/starwars-api80.csproj +++ b/src/ancillary-projects/starwars/starwars-api90/starwars-api90.csproj @@ -1,7 +1,7 @@ - net8.0 + net9.0 latest $(NoWarn);1701;1702;1705;1591;NU1603 GraphQL.AspNet.StarWarsAPI6X diff --git a/src/ancillary-projects/starwars/starwars-common/starwars-common.csproj b/src/ancillary-projects/starwars/starwars-common/starwars-common.csproj index cdf1f0fc5..07a7716b1 100644 --- a/src/ancillary-projects/starwars/starwars-common/starwars-common.csproj +++ b/src/ancillary-projects/starwars/starwars-common/starwars-common.csproj @@ -1,7 +1,7 @@  - net8.0;net7.0;netstandard2.0; + net9.0;net8.0;netstandard2.0; latest $(NoWarn);1701;1702;1705;1591;NU1603 GraphQL.AspNet.StarwarsAPI.Common diff --git a/src/graphql-aspnet-subscriptions/Web/WebSockets/WebSocketClientConnection.cs b/src/graphql-aspnet-subscriptions/Web/WebSockets/WebSocketClientConnection.cs index 2dc728677..e5cf9a73d 100644 --- a/src/graphql-aspnet-subscriptions/Web/WebSockets/WebSocketClientConnection.cs +++ b/src/graphql-aspnet-subscriptions/Web/WebSockets/WebSocketClientConnection.cs @@ -56,7 +56,7 @@ private string DeteremineRequestedProtocol() if (_httpContext.Request.Headers.ContainsKey(SubscriptionConstants.WebSockets.WEBSOCKET_PROTOCOL_HEADER)) { var protocolHeaders = _httpContext.Request.Headers[SubscriptionConstants.WebSockets.WEBSOCKET_PROTOCOL_HEADER]; - return string.Join(",", protocolHeaders); + return string.Join(",", protocolHeaders.ToArray()); } return string.Empty; diff --git a/src/graphql-aspnet.sln b/src/graphql-aspnet.sln index f3978b89f..ac80d2c73 100644 --- a/src/graphql-aspnet.sln +++ b/src/graphql-aspnet.sln @@ -33,10 +33,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "graphql-aspnet-subscription EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "graphql-aspnet-tests-common", "unit-tests\graphql-aspnet-tests-common\graphql-aspnet-tests-common.csproj", "{3CB086E3-5E7B-438B-9A95-AEA264009521}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "starwars-api80", "ancillary-projects\starwars\starwars-api80\starwars-api80.csproj", "{43C9EB6E-5FFE-4EC6-B21B-09C715B7B114}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "graphql-aspnet-testframework-tests", "unit-tests\graphql-aspnet-testframework-tests\graphql-aspnet-testframework-tests.csproj", "{E67D4FB2-73FF-4EC1-80F8-5D4DEC57F5AA}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "starwars-api90", "ancillary-projects\starwars\starwars-api90\starwars-api90.csproj", "{E7EE5851-57F1-4E20-B4BA-06902C77E83A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -72,14 +72,14 @@ Global {3CB086E3-5E7B-438B-9A95-AEA264009521}.Debug|Any CPU.Build.0 = Debug|Any CPU {3CB086E3-5E7B-438B-9A95-AEA264009521}.Release|Any CPU.ActiveCfg = Release|Any CPU {3CB086E3-5E7B-438B-9A95-AEA264009521}.Release|Any CPU.Build.0 = Release|Any CPU - {43C9EB6E-5FFE-4EC6-B21B-09C715B7B114}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {43C9EB6E-5FFE-4EC6-B21B-09C715B7B114}.Debug|Any CPU.Build.0 = Debug|Any CPU - {43C9EB6E-5FFE-4EC6-B21B-09C715B7B114}.Release|Any CPU.ActiveCfg = Release|Any CPU - {43C9EB6E-5FFE-4EC6-B21B-09C715B7B114}.Release|Any CPU.Build.0 = Release|Any CPU {E67D4FB2-73FF-4EC1-80F8-5D4DEC57F5AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E67D4FB2-73FF-4EC1-80F8-5D4DEC57F5AA}.Debug|Any CPU.Build.0 = Debug|Any CPU {E67D4FB2-73FF-4EC1-80F8-5D4DEC57F5AA}.Release|Any CPU.ActiveCfg = Release|Any CPU {E67D4FB2-73FF-4EC1-80F8-5D4DEC57F5AA}.Release|Any CPU.Build.0 = Release|Any CPU + {E7EE5851-57F1-4E20-B4BA-06902C77E83A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E7EE5851-57F1-4E20-B4BA-06902C77E83A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E7EE5851-57F1-4E20-B4BA-06902C77E83A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E7EE5851-57F1-4E20-B4BA-06902C77E83A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -91,8 +91,8 @@ Global {5DE081AA-494A-4377-B2CA-6952715D513D} = {350D3594-5D97-4D9B-A01D-D3A5C036318C} {6E4A16F5-1B98-412E-9A88-F56301F5D0E4} = {350D3594-5D97-4D9B-A01D-D3A5C036318C} {3CB086E3-5E7B-438B-9A95-AEA264009521} = {350D3594-5D97-4D9B-A01D-D3A5C036318C} - {43C9EB6E-5FFE-4EC6-B21B-09C715B7B114} = {22C7BC5B-EC8E-4A07-9968-961E86AB44E2} {E67D4FB2-73FF-4EC1-80F8-5D4DEC57F5AA} = {350D3594-5D97-4D9B-A01D-D3A5C036318C} + {E7EE5851-57F1-4E20-B4BA-06902C77E83A} = {22C7BC5B-EC8E-4A07-9968-961E86AB44E2} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {DD2C38B8-B029-4DE1-877E-B1A661AC412F} diff --git a/src/graphql-aspnet.sln.DotSettings b/src/graphql-aspnet.sln.DotSettings index fd6abeb25..280d05ffe 100644 --- a/src/graphql-aspnet.sln.DotSettings +++ b/src/graphql-aspnet.sln.DotSettings @@ -246,7 +246,7 @@ graphql-aspnet repo: https://github.com/kevin-carroll/graphql-aspnet docs: -coming soon- -- -project: $PROJECT$ +project: ${File.ProjectName} -- License: MIT ************************************************************* @@ -265,6 +265,10 @@ License: MIT <Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB"><ExtraRule Prefix="ERROR_" Suffix="" Style="AA_BB" /></Policy> <Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /> + <Policy><Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static readonly fields (private)"><ElementKinds><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /></Policy> + <Policy><Descriptor Staticness="Any" AccessRightKinds="Private" Description="Constant fields (private)"><ElementKinds><Kind Name="CONSTANT_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB"><ExtraRule Prefix="ERROR_" Suffix="" Style="AA_BB" /></Policy></Policy> + <Policy><Descriptor Staticness="Any" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Constant fields (not private)"><ElementKinds><Kind Name="CONSTANT_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB"><ExtraRule Prefix="ERROR_" Suffix="" Style="AA_BB" /></Policy></Policy> + <Policy><Descriptor Staticness="Any" AccessRightKinds="Any" Description="Types and namespaces"><ElementKinds><Kind Name="NAMESPACE" /><Kind Name="CLASS" /><Kind Name="STRUCT" /><Kind Name="ENUM" /><Kind Name="DELEGATE" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /></Policy> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> @@ -337,6 +341,7 @@ License: MIT NOTIFY True + True True True True @@ -345,11 +350,13 @@ License: MIT True True True + True True True True True True + True True 3 diff --git a/src/graphql-aspnet/Execution/QueryPlans/DocumentParts/DocumentNamedFragmentCollection.cs b/src/graphql-aspnet/Execution/QueryPlans/DocumentParts/DocumentNamedFragmentCollection.cs index 45adcbb81..406a5a942 100644 --- a/src/graphql-aspnet/Execution/QueryPlans/DocumentParts/DocumentNamedFragmentCollection.cs +++ b/src/graphql-aspnet/Execution/QueryPlans/DocumentParts/DocumentNamedFragmentCollection.cs @@ -13,16 +13,17 @@ namespace GraphQL.AspNet.Execution.QueryPlans.DocumentParts using System.Collections.Generic; using System.Diagnostics; using GraphQL.AspNet.Common; - using GraphQL.AspNet.Common.Generics; using GraphQL.AspNet.Interfaces.Execution.QueryPlans.DocumentParts; + using OrderedDictionaryOfStringAndNamedFragment = GraphQL.AspNet.Common.Generics.OrderedDictionary; + /// /// An indexed collection of named fragments contained within a query document. /// [DebuggerDisplay("Count = {Count}")] internal class DocumentNamedFragmentCollection : INamedFragmentCollectionDocumentPart { - private OrderedDictionary _fragments; + private OrderedDictionaryOfStringAndNamedFragment _fragments; // its possible that a document declares more than one named fragment with the same // name. Keep track of the duplicates for document validation reporting. @@ -35,7 +36,7 @@ internal class DocumentNamedFragmentCollection : INamedFragmentCollectionDocumen public DocumentNamedFragmentCollection(IDocumentPart parent) { this.Parent = Validation.ThrowIfNullOrReturn(parent, nameof(parent)); - _fragments = new OrderedDictionary(); + _fragments = new OrderedDictionaryOfStringAndNamedFragment(); } /// diff --git a/src/graphql-aspnet/Execution/Response/ResponseFieldSet.cs b/src/graphql-aspnet/Execution/Response/ResponseFieldSet.cs index 1170099d0..208976e2a 100644 --- a/src/graphql-aspnet/Execution/Response/ResponseFieldSet.cs +++ b/src/graphql-aspnet/Execution/Response/ResponseFieldSet.cs @@ -11,23 +11,24 @@ namespace GraphQL.AspNet.Execution.Response { using System.Collections.Generic; using System.Diagnostics; - using GraphQL.AspNet.Common.Generics; using GraphQL.AspNet.Interfaces.Execution.Response; + using OrderedDictionaryOfStringAndQueryResponseItem = GraphQL.AspNet.Common.Generics.OrderedDictionary; + /// /// A collection of keyed items included as a result to a graphql query. /// [DebuggerDisplay("Count = {Fields.Count}")] internal class ResponseFieldSet : IQueryResponseFieldSet { - private readonly OrderedDictionary _dictionary; + private readonly OrderedDictionaryOfStringAndQueryResponseItem _dictionary; /// /// Initializes a new instance of the class. /// public ResponseFieldSet() { - _dictionary = new OrderedDictionary(); + _dictionary = new OrderedDictionaryOfStringAndQueryResponseItem(); } /// diff --git a/src/graphql-aspnet/Schemas/Structural/GraphFieldArgumentCollection.cs b/src/graphql-aspnet/Schemas/Structural/GraphFieldArgumentCollection.cs index 519cb6692..38b33ac68 100644 --- a/src/graphql-aspnet/Schemas/Structural/GraphFieldArgumentCollection.cs +++ b/src/graphql-aspnet/Schemas/Structural/GraphFieldArgumentCollection.cs @@ -14,10 +14,11 @@ namespace GraphQL.AspNet.Schemas.Structural using System.Collections.Generic; using System.Diagnostics; using GraphQL.AspNet.Common; - using GraphQL.AspNet.Common.Generics; using GraphQL.AspNet.Interfaces.Schema; using GraphQL.AspNet.Schemas.TypeSystem; + using OrderedDictionaryOfStringAndGraphArgument = GraphQL.AspNet.Common.Generics.OrderedDictionary; + /// /// A collection of allowed arguments defined for a or . /// @@ -25,7 +26,7 @@ namespace GraphQL.AspNet.Schemas.Structural internal class GraphFieldArgumentCollection : IGraphArgumentCollection { private readonly ISchemaItem _owner; - private readonly OrderedDictionary _arguments; + private readonly OrderedDictionaryOfStringAndGraphArgument _arguments; private IGraphArgument _sourceArgument; /// @@ -36,7 +37,7 @@ internal class GraphFieldArgumentCollection : IGraphArgumentCollection public GraphFieldArgumentCollection(ISchemaItem owner) { _owner = Validation.ThrowIfNullOrReturn(owner, nameof(owner)); - _arguments = new OrderedDictionary(StringComparer.Ordinal); + _arguments = new OrderedDictionaryOfStringAndGraphArgument(StringComparer.Ordinal); } /// diff --git a/src/graphql-aspnet/Schemas/TypeSystem/Introspection/Model/IntrospectedSchema.cs b/src/graphql-aspnet/Schemas/TypeSystem/Introspection/Model/IntrospectedSchema.cs index 0eff5c0bb..821a66f69 100644 --- a/src/graphql-aspnet/Schemas/TypeSystem/Introspection/Model/IntrospectedSchema.cs +++ b/src/graphql-aspnet/Schemas/TypeSystem/Introspection/Model/IntrospectedSchema.cs @@ -16,11 +16,12 @@ namespace GraphQL.AspNet.Schemas.TypeSystem.Introspection.Model using GraphQL.AspNet.Attributes; using GraphQL.AspNet.Common; using GraphQL.AspNet.Common.Extensions; - using GraphQL.AspNet.Common.Generics; using GraphQL.AspNet.Execution.Exceptions; using GraphQL.AspNet.Interfaces.Schema; using GraphQL.AspNet.Schemas.TypeSystem; + using OrderedDictionaryOfStringAndType = GraphQL.AspNet.Common.Generics.OrderedDictionary; + /// /// A model object containing data for the '__Schema' type. /// @@ -28,7 +29,7 @@ namespace GraphQL.AspNet.Schemas.TypeSystem.Introspection.Model public sealed class IntrospectedSchema : IntrospectedItem, ISchemaItem { private readonly ISchema _schema; - private OrderedDictionary _typeList; + private OrderedDictionaryOfStringAndType _typeList; private List _directiveList; /// @@ -39,7 +40,7 @@ public IntrospectedSchema(ISchema schema) : base(schema) { _schema = Validation.ThrowIfNullOrReturn(schema, nameof(schema)); - _typeList = new OrderedDictionary(); + _typeList = new OrderedDictionaryOfStringAndType(); } /// @@ -72,7 +73,7 @@ private void RebuildDirectiveList() private void RebuildIntrospectedTypeList() { _typeList.Clear(); - _typeList = new OrderedDictionary(); + _typeList = new OrderedDictionaryOfStringAndType(); // build in a two pass approach // ----------------------------------------- diff --git a/src/library-common.props b/src/library-common.props index eacbad505..31a4b789c 100644 --- a/src/library-common.props +++ b/src/library-common.props @@ -1,7 +1,7 @@ - net8.0;net6.0;netstandard2.0; + net9.0;net8.0;netstandard2.0; latest $(NoWarn);1701;1702;1705;1591;NU1603;IDE0019;IDE0017;RCS1146;RCS1194; diff --git a/src/library-tests.props b/src/library-tests.props index 5d3fee9ea..0b086b1ea 100644 --- a/src/library-tests.props +++ b/src/library-tests.props @@ -1,7 +1,7 @@ - net8.0;net6.0; + net9.0;net8.0; latest $(NoWarn);1701;1702;1705;1591;NU1603;IDE0019;IDE0017;RCS1146;RCS1194; GraphQL.AspNet.Tests diff --git a/src/unit-tests/graphql-aspnet-testframework/graphql-aspnet-testframework.csproj b/src/unit-tests/graphql-aspnet-testframework/graphql-aspnet-testframework.csproj index d294329bb..31430a712 100644 --- a/src/unit-tests/graphql-aspnet-testframework/graphql-aspnet-testframework.csproj +++ b/src/unit-tests/graphql-aspnet-testframework/graphql-aspnet-testframework.csproj @@ -2,7 +2,7 @@ - net8.0;net7.0;net6.0; + net9.0;net8.0; GraphQL.AspNet.Tests.Framework GraphQL.AspNet.TestFramework GraphQL ASP.NET Test Framework diff --git a/src/unit-tests/graphql-aspnet-tests-thirdpartydll/graphql-aspnet-tests-thirdpartydll.csproj b/src/unit-tests/graphql-aspnet-tests-thirdpartydll/graphql-aspnet-tests-thirdpartydll.csproj index fa889e4e6..ccb585eab 100644 --- a/src/unit-tests/graphql-aspnet-tests-thirdpartydll/graphql-aspnet-tests-thirdpartydll.csproj +++ b/src/unit-tests/graphql-aspnet-tests-thirdpartydll/graphql-aspnet-tests-thirdpartydll.csproj @@ -1,7 +1,7 @@  - net8.0;net7.0;net6.0; + net9.0;net8.0; latest $(NoWarn);1701;1702;1705;1591;NU1603;IDE0060;IDE0052;IDE0044;IDE0059;IDE0052 GraphQL.AspNet.Tests.ThirdPartyDll diff --git a/src/unit-tests/graphql-aspnet-tests/Common/OrderedDictionaryTests.cs b/src/unit-tests/graphql-aspnet-tests/Common/OrderedDictionaryTests.cs index ef8174de5..e56e4398d 100644 --- a/src/unit-tests/graphql-aspnet-tests/Common/OrderedDictionaryTests.cs +++ b/src/unit-tests/graphql-aspnet-tests/Common/OrderedDictionaryTests.cs @@ -16,13 +16,15 @@ namespace GraphQL.AspNet.Tests.Common using System.Linq; using GraphQL.AspNet.Common.Generics; using NUnit.Framework; + using OrderedDictionaryOfStringAndInt = GraphQL.AspNet.Common.Generics.OrderedDictionary; + using OrderedDictionaryOfStringAndString = GraphQL.AspNet.Common.Generics.OrderedDictionary; [TestFixture] public class OrderedDictionaryTests { - private OrderedDictionary GetAlphabetDictionary(IEqualityComparer comparer = null) + private OrderedDictionaryOfStringAndString GetAlphabetDictionary(IEqualityComparer comparer = null) { - OrderedDictionary alphabet = new OrderedDictionary(comparer); + OrderedDictionaryOfStringAndString alphabet = new OrderedDictionaryOfStringAndString(comparer); for (var a = Convert.ToInt32('a'); a <= Convert.ToInt32('z'); a++) { var c = Convert.ToChar(a); @@ -57,11 +59,11 @@ public int Compare(int x, int y) [Test] public void Constructor_FromOtherDictionary() { - var od = new OrderedDictionary(); + var od = new OrderedDictionaryOfStringAndString(); od.Add("key1", "value1"); od.Add("key2", "value2"); - var od2 = new OrderedDictionary(od); + var od2 = new OrderedDictionaryOfStringAndString(od); Assert.AreEqual(2, od2.Count); Assert.AreEqual("value1", od2["key1"]); Assert.AreEqual("value2", od2["key2"]); @@ -70,12 +72,12 @@ public void Constructor_FromOtherDictionary() [Test] public void Constructor_FromOtherDictionary_CaseInsensitive() { - var od = new OrderedDictionary(); + var od = new OrderedDictionaryOfStringAndString(); od.Add("key1", "value1"); od.Add("key2", "value2"); Assert.IsFalse(od.ContainsKey("KEY1")); - var od2 = new OrderedDictionary(od, StringComparer.InvariantCultureIgnoreCase); + var od2 = new OrderedDictionaryOfStringAndString(od, StringComparer.InvariantCultureIgnoreCase); Assert.AreEqual(2, od2.Count); Assert.AreEqual("value1", od2["KEY1"]); Assert.AreEqual("value2", od2["KEY2"]); @@ -84,7 +86,7 @@ public void Constructor_FromOtherDictionary_CaseInsensitive() [Test] public void Browser_PropertyCheck() { - var dic = new OrderedDictionary(); + var dic = new OrderedDictionaryOfStringAndInt(); dic.Add("key1", 1); dic.Add("key2", 2); @@ -110,7 +112,7 @@ public void Browser_PropertyCheck() [Test] public void DuplicateAdd_ThrowsError() { - var dic = new OrderedDictionary(); + var dic = new OrderedDictionaryOfStringAndInt(); dic.Add("key1", 1); Assert.Throws(() => { dic.Add("key1", 1); }); @@ -119,7 +121,7 @@ public void DuplicateAdd_ThrowsError() [Test] public void ICollectionKVP_CastingCheck() { - var dic = new OrderedDictionary(); + var dic = new OrderedDictionaryOfStringAndInt(); var kvp = new KeyValuePair("key1", 3); var col = dic as ICollection>; @@ -149,7 +151,7 @@ public void ICollectionKVP_CastingCheck() [Test] public void IDicionaryKVP_CastingCheck() { - var od = new OrderedDictionary() as IDictionary; + var od = new OrderedDictionaryOfStringAndString() as IDictionary; Assert.AreEqual(0, od.Count); od.Add("foo", "bar"); @@ -182,7 +184,7 @@ public void IDicionaryKVP_CastingCheck() [Test] public void IOrderedDictionary_CastingCheck() { - var od = new OrderedDictionary() as IOrderedDictionary; + var od = new OrderedDictionaryOfStringAndString() as IOrderedDictionary; Assert.AreEqual(0, od.Count); // IOrderedDictionary.Insert @@ -252,7 +254,7 @@ public void IDictionary_CastingCheck() [Test] public void Add() { - var od = new OrderedDictionary(); + var od = new OrderedDictionaryOfStringAndString(); Assert.AreEqual(0, od.Count); Assert.AreEqual(-1, od.IndexOf("foo")); @@ -268,7 +270,7 @@ public void Add() [Test] public void Remove() { - var od = new OrderedDictionary(); + var od = new OrderedDictionaryOfStringAndString(); od.Add("foo", "bar"); Assert.AreEqual(1, od.Count); @@ -280,7 +282,7 @@ public void Remove() [Test] public void RemoveAt() { - var od = new OrderedDictionary(); + var od = new OrderedDictionaryOfStringAndString(); od.Add("foo", "bar"); Assert.AreEqual(1, od.Count); @@ -585,7 +587,7 @@ public void DelegateKeyCollection_PropertyCheck() [Test] public void DictionaryEnumerator_Reset_YieldsFirstItemAgain() { - var dic = new OrderedDictionary(); + var dic = new OrderedDictionaryOfStringAndString(); dic.Add("a", "string1"); dic.Add("b", "string2"); @@ -604,7 +606,7 @@ public void DictionaryEnumerator_Reset_YieldsFirstItemAgain() [Test] public void DictionaryEnumerator_PropertyCheck() { - var dic = new OrderedDictionary(); + var dic = new OrderedDictionaryOfStringAndString(); dic.Add("a", "string1"); dic.Add("b", "string2"); From 54a16aad1dd12a10d6ca8265f6054dfb103ee1ca Mon Sep 17 00:00:00 2001 From: Kevin Carroll Date: Fri, 25 Apr 2025 08:02:42 -0700 Subject: [PATCH 6/7] Fix for Subscription Message Serialziation (#169) * Fixed a bug where some client libraries would reject subscription messages due to erroneous id values. --- .github/workflows/ci-build.yml | 2 +- .github/workflows/nuget-deployment.yml | 2 +- .../Properties/launchSettings.json | 2 +- .../GraphqlTransportWs/GqltwsClientProxy.cs | 1 + .../GraphqlWsLegacyClientProxy.cs | 3 ++- src/graphql-aspnet/Common/TimerAsync.cs | 8 ++++--- .../GraphqlTransportWs/GqltwsClientAsserts.cs | 23 +++++++++++-------- .../GqltwsClientProxyTests.cs | 18 +++++++++++++++ .../GraphqlWsLegacyClientAsserts.cs | 23 +++++++++++-------- .../GraphqlWsLegacyClientProxyTests.cs | 18 +++++++++++++++ 10 files changed, 75 insertions(+), 25 deletions(-) diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index da3496987..944272036 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -24,7 +24,7 @@ env: jobs: build: name: Sanity Build - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/nuget-deployment.yml b/.github/workflows/nuget-deployment.yml index d9be6e265..5a544ae79 100644 --- a/.github/workflows/nuget-deployment.yml +++ b/.github/workflows/nuget-deployment.yml @@ -26,7 +26,7 @@ env: jobs: deployment: name: Pack & Deploy - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v3 diff --git a/src/ancillary-projects/starwars/starwars-api90/Properties/launchSettings.json b/src/ancillary-projects/starwars/starwars-api90/Properties/launchSettings.json index 34bbebbd8..837d831d9 100644 --- a/src/ancillary-projects/starwars/starwars-api90/Properties/launchSettings.json +++ b/src/ancillary-projects/starwars/starwars-api90/Properties/launchSettings.json @@ -1,7 +1,7 @@ { "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { - "StarWars: .NET 8": { + "StarWars: .NET 9": { "commandName": "Project", "applicationUrl": "http://localhost:5000", "environmentVariables": { diff --git a/src/graphql-aspnet-subscriptions/SubscriptionServer/Protocols/GraphqlTransportWs/GqltwsClientProxy.cs b/src/graphql-aspnet-subscriptions/SubscriptionServer/Protocols/GraphqlTransportWs/GqltwsClientProxy.cs index 422325740..e023e335c 100644 --- a/src/graphql-aspnet-subscriptions/SubscriptionServer/Protocols/GraphqlTransportWs/GqltwsClientProxy.cs +++ b/src/graphql-aspnet-subscriptions/SubscriptionServer/Protocols/GraphqlTransportWs/GqltwsClientProxy.cs @@ -94,6 +94,7 @@ public GqltwsClientProxy( _serializerOptions.Converters.Add(new GqltwsServerDataMessageConverter(schema, responseWriter)); _serializerOptions.Converters.Add(new GqltwsServerCompleteMessageConverter()); _serializerOptions.Converters.Add(new GqltwsServerErrorMessageConverter(schema)); + _serializerOptions.Converters.Add(new GqltwsMessageConverter()); } /// diff --git a/src/graphql-aspnet-subscriptions/SubscriptionServer/Protocols/GraphqlWsLegacy/GraphqlWsLegacyClientProxy.cs b/src/graphql-aspnet-subscriptions/SubscriptionServer/Protocols/GraphqlWsLegacy/GraphqlWsLegacyClientProxy.cs index 0b4bc66e4..2c580f9bb 100644 --- a/src/graphql-aspnet-subscriptions/SubscriptionServer/Protocols/GraphqlWsLegacy/GraphqlWsLegacyClientProxy.cs +++ b/src/graphql-aspnet-subscriptions/SubscriptionServer/Protocols/GraphqlWsLegacy/GraphqlWsLegacyClientProxy.cs @@ -93,6 +93,7 @@ public GraphqlWsLegacyClientProxy( _serializeOptions.Converters.Add(new GraphqlWsLegacyServerDataMessageConverter(schema, responseWriter)); _serializeOptions.Converters.Add(new GraphqlWsLegacyServerCompleteMessageConverter()); _serializeOptions.Converters.Add(new GraphqlWsLegacyServerErrorMessageConverter(schema)); + _serializeOptions.Converters.Add(new GraphqlWsLegacyMessageConverter()); } /// @@ -305,7 +306,7 @@ private async Task AcknowledgeNewConnectionAsync() /// protected override async Task ExecuteKeepAliveAsync(CancellationToken cancelToken = default) { - await this.SendMessageAsync(new GraphqlWsLegacyKeepAliveOperationMessage()); + await this.SendMessageAsync(new GraphqlWsLegacyKeepAliveOperationMessage(), cancelToken); } /// diff --git a/src/graphql-aspnet/Common/TimerAsync.cs b/src/graphql-aspnet/Common/TimerAsync.cs index 6fd016c72..2cf02f354 100644 --- a/src/graphql-aspnet/Common/TimerAsync.cs +++ b/src/graphql-aspnet/Common/TimerAsync.cs @@ -90,7 +90,8 @@ public void Start() } finally { - _semaphore.Release(); + if (!_disposed) + _semaphore.Release(); } } @@ -121,7 +122,8 @@ public async Task StopAsync() finally { this.IsRunning = false; - _semaphore.Release(); + if (!_disposed) + _semaphore.Release(); } } @@ -195,4 +197,4 @@ public void Dispose() /// true if the timer is running; otherwise, false. public bool IsRunning { get; private set; } } -} +} \ No newline at end of file diff --git a/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlTransportWs/GqltwsClientAsserts.cs b/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlTransportWs/GqltwsClientAsserts.cs index 9cd2488b7..a902cb612 100644 --- a/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlTransportWs/GqltwsClientAsserts.cs +++ b/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlTransportWs/GqltwsClientAsserts.cs @@ -25,12 +25,13 @@ public static class GqltwsClientAsserts /// The connection. /// The type of message to check for. /// if true, the message is removed from the queue. - internal static void AssertGqltwsResponse( + /// The raw string data (usually json formatted) of the message data recevied by the connection proxy + internal static string AssertGqltwsResponse( this MockClientConnection connection, GqltwsMessageType type, bool dequeue = true) { - connection.AssertGqltwsResponse(type, null, false, null, false, dequeue); + return connection.AssertGqltwsResponse(type, null, false, null, false, dequeue); } /// @@ -40,13 +41,14 @@ internal static void AssertGqltwsResponse( /// The type of message to check for. /// The id returned by the server, if supplied. /// if true, the message is removed from the queue. - internal static void AssertGqltwsResponse( + /// The raw string data (usually json formatted) of the message data recevied by the connection proxy + internal static string AssertGqltwsResponse( this MockClientConnection connection, GqltwsMessageType type, string id, bool dequeue = true) { - connection.AssertGqltwsResponse(type, id, true, null, false, dequeue); + return connection.AssertGqltwsResponse(type, id, true, null, false, dequeue); } /// @@ -58,17 +60,18 @@ internal static void AssertGqltwsResponse( /// The expected identifier of the subscription that rendered the data. /// The expected payload of the message, converted to a json string. /// if set to true if the message should be removed from the queue. - internal static void AssertGqltwsResponse( + /// The raw string data (usually json formatted) of the message data recevied by the connection proxy + internal static string AssertGqltwsResponse( this MockClientConnection connection, GqltwsMessageType type, string id, string expectedPayloadJson, bool dequeue = true) { - connection.AssertGqltwsResponse(type, id, true, expectedPayloadJson, true, dequeue); + return connection.AssertGqltwsResponse(type, id, true, expectedPayloadJson, true, dequeue); } - private static void AssertGqltwsResponse( + private static string AssertGqltwsResponse( this MockClientConnection connection, GqltwsMessageType type, string id, @@ -81,14 +84,14 @@ private static void AssertGqltwsResponse( Assert.Fail("No messages queued."); var message = dequeue ? connection.DequeueNextReceivedMessage() : connection.PeekNextReceivedMessage(); - var str = Encoding.UTF8.GetString(message.Data); + var rawMessageData = Encoding.UTF8.GetString(message.Data); var options = new JsonSerializerOptions(); options.PropertyNameCaseInsensitive = true; options.AllowTrailingCommas = true; options.Converters.Add(new GqltwsResponseMessageConverter()); - var convertedMessage = JsonSerializer.Deserialize(str, options); + var convertedMessage = JsonSerializer.Deserialize(rawMessageData, options); Assert.IsNotNull(convertedMessage, "Could not deserialize response message"); Assert.AreEqual(type, convertedMessage.Type, $"Expected message type of {type.ToString()} but got {convertedMessage.Type.ToString()}"); @@ -103,6 +106,8 @@ private static void AssertGqltwsResponse( if (compareId) Assert.AreEqual(id, convertedMessage.Id); + + return rawMessageData; } } } \ No newline at end of file diff --git a/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlTransportWs/GqltwsClientProxyTests.cs b/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlTransportWs/GqltwsClientProxyTests.cs index 31b2cdfc0..533890d27 100644 --- a/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlTransportWs/GqltwsClientProxyTests.cs +++ b/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlTransportWs/GqltwsClientProxyTests.cs @@ -746,5 +746,23 @@ public async Task Deserialize_InvalidMessage_ProcessesUnknownMessage() connection.AssertServerClosedConnection((ConnectionCloseStatus)GqltwsConstants.CustomCloseEventIds.InvalidMessageType); graphqlWsClient.Dispose(); } + + [Test] + public async Task SendConnectionInitMessage_RespondsWithCorrectAckMessage() + { + using var restorePoint = new GraphQLGlobalSubscriptionRestorePoint(); + (var socketClient, var client, var router) = this.CreateConnection(); + + socketClient.QueueClientMessage(new GqltwsClientConnectionInitMessage()); + socketClient.QueueConnectionClosedByClient(); + + await client.StartConnectionAsync(); + + var rawMessageData = socketClient.AssertGqltwsResponse(GqltwsMessageType.CONNECTION_ACK); + socketClient.AssertClientClosedConnection(); + + var expectedData = "{ \"type\": \"connection_ack\" }"; + CommonAssertions.AreEqualJsonStrings(expectedData, rawMessageData); + } } } \ No newline at end of file diff --git a/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlWsLegacy/GraphqlWsLegacyClientAsserts.cs b/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlWsLegacy/GraphqlWsLegacyClientAsserts.cs index ca3609107..45937a07f 100644 --- a/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlWsLegacy/GraphqlWsLegacyClientAsserts.cs +++ b/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlWsLegacy/GraphqlWsLegacyClientAsserts.cs @@ -25,12 +25,13 @@ public static class GraphqlWsLegacyClientAsserts /// The connection. /// The type of message to check for. /// if true, the message is removed from the queue. - internal static void AssertGraphqlWsLegacyResponse( + /// The raw string data (usually json formatted) of the message data recevied by the connection proxy + internal static string AssertGraphqlWsLegacyResponse( this MockClientConnection connection, GraphqlWsLegacyMessageType type, bool dequeue = true) { - connection.AssertGraphqlWsLegacyResponse(type, null, false, null, false, dequeue); + return connection.AssertGraphqlWsLegacyResponse(type, null, false, null, false, dequeue); } /// @@ -40,13 +41,14 @@ internal static void AssertGraphqlWsLegacyResponse( /// The type of message to check for. /// The id returned by the server, if supplied. /// if true, the message is removed from the queue. - internal static void AssertGraphqlWsLegacyResponse( + /// The raw string data (usually json formatted) of the message data recevied by the connection proxy + internal static string AssertGraphqlWsLegacyResponse( this MockClientConnection connection, GraphqlWsLegacyMessageType type, string id, bool dequeue = true) { - connection.AssertGraphqlWsLegacyResponse(type, id, true, null, false, dequeue); + return connection.AssertGraphqlWsLegacyResponse(type, id, true, null, false, dequeue); } /// @@ -58,17 +60,18 @@ internal static void AssertGraphqlWsLegacyResponse( /// The expected identifier of the subscription that rendered the data. /// The expected payload of the message, converted to a json string. /// if set to true if the message should be removed from the queue. - internal static void AssertGraphqlWsLegacyResponse( + /// The raw string data (usually json formatted) of the message data recevied by the connection proxy + internal static string AssertGraphqlWsLegacyResponse( this MockClientConnection connection, GraphqlWsLegacyMessageType type, string id, string expectedPayloadJson, bool dequeue = true) { - connection.AssertGraphqlWsLegacyResponse(type, id, true, expectedPayloadJson, true, dequeue); + return connection.AssertGraphqlWsLegacyResponse(type, id, true, expectedPayloadJson, true, dequeue); } - private static void AssertGraphqlWsLegacyResponse( + private static string AssertGraphqlWsLegacyResponse( this MockClientConnection connection, GraphqlWsLegacyMessageType type, string id, @@ -81,14 +84,14 @@ private static void AssertGraphqlWsLegacyResponse( Assert.Fail("No messages queued."); var message = dequeue ? connection.DequeueNextReceivedMessage() : connection.PeekNextReceivedMessage(); - var str = Encoding.UTF8.GetString(message.Data); + var rawData = Encoding.UTF8.GetString(message.Data); var options = new JsonSerializerOptions(); options.PropertyNameCaseInsensitive = true; options.AllowTrailingCommas = true; options.Converters.Add(new GraphqlWsLegacyResponseMessageConverter()); - var convertedMessage = JsonSerializer.Deserialize(str, options); + var convertedMessage = JsonSerializer.Deserialize(rawData, options); Assert.IsNotNull(convertedMessage, "Could not deserialized response message"); Assert.AreEqual(type, convertedMessage.Type, $"Expected message type of {type.ToString()} but got {convertedMessage.Type.ToString()}"); @@ -103,6 +106,8 @@ private static void AssertGraphqlWsLegacyResponse( if (compareId) Assert.AreEqual(id, convertedMessage.Id); + + return rawData; } } } \ No newline at end of file diff --git a/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlWsLegacy/GraphqlWsLegacyClientProxyTests.cs b/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlWsLegacy/GraphqlWsLegacyClientProxyTests.cs index 4bf1a0865..0547ee6ea 100644 --- a/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlWsLegacy/GraphqlWsLegacyClientProxyTests.cs +++ b/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlWsLegacy/GraphqlWsLegacyClientProxyTests.cs @@ -501,5 +501,23 @@ public async Task Deserialize_InvalidMessage_ProcessesUnknownMessage() socketClient.AssertGraphqlWsLegacyResponse(GraphqlWsLegacyMessageType.ERROR); socketClient.AssertClientClosedConnection(); } + + [Test] + public async Task SendConnectionInitMessage_RespondsWithCorrectAckMessage() + { + using var restorePoint = new GraphQLGlobalSubscriptionRestorePoint(); + (var socketClient, var client, var router) = this.CreateConnection(); + + socketClient.QueueClientMessage(new GraphqlWsLegacyClientConnectionInitMessage()); + socketClient.QueueConnectionClosedByClient(); + + await client.StartConnectionAsync(); + + var rawMessageData = socketClient.AssertGraphqlWsLegacyResponse(GraphqlWsLegacyMessageType.CONNECTION_ACK); + socketClient.AssertClientClosedConnection(); + + var expectedData = "{ \"type\": \"connection_ack\" }"; + CommonAssertions.AreEqualJsonStrings(expectedData, rawMessageData); + } } } \ No newline at end of file From ea04bdb404c9d269307ecf30c87b67d3fa0e0de5 Mon Sep 17 00:00:00 2001 From: Kevin Carroll Date: Fri, 25 Apr 2025 08:24:08 -0700 Subject: [PATCH 7/7] Update deployment action steps (#170) * Updates dotnet setup version to v4 * Updates upload-artifacts version to v4 --- .github/workflows/ci-build.yml | 2 +- .github/workflows/nuget-deployment.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index 944272036..db642b372 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -33,7 +33,7 @@ jobs: # --------------------------------------- # Install .NET Versions # --------------------------------------- - - uses: actions/setup-dotnet@v2 + - uses: actions/setup-dotnet@v4 name: Install .NET with: dotnet-version: | diff --git a/.github/workflows/nuget-deployment.yml b/.github/workflows/nuget-deployment.yml index 5a544ae79..02cecd95f 100644 --- a/.github/workflows/nuget-deployment.yml +++ b/.github/workflows/nuget-deployment.yml @@ -35,7 +35,7 @@ jobs: # --------------------------------------- # Install .NET Versions # --------------------------------------- - - uses: actions/setup-dotnet@v2 + - uses: actions/setup-dotnet@v4 name: Install .NET with: dotnet-version: | @@ -77,7 +77,7 @@ jobs: # --------------------------------------- # Save Artifacts for later debugging # --------------------------------------- - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 name: Save Artifacts with: name: generated-nuget-packages