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/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) 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); + } + } +}