diff --git a/src/CoreTests/all_exceptions_should_derive_from_MartenException.cs b/src/CoreTests/all_exceptions_should_derive_from_MartenException.cs index b0704cd9dd..b9db17d9ce 100644 --- a/src/CoreTests/all_exceptions_should_derive_from_MartenException.cs +++ b/src/CoreTests/all_exceptions_should_derive_from_MartenException.cs @@ -3,7 +3,7 @@ using System.Linq; using JasperFx.Core; using JasperFx.Core.Reflection; -using Marten.Events.TestSupport; +using JasperFx.Events.TestSupport; using Marten.Exceptions; using Shouldly; using Xunit; diff --git a/src/DaemonTests/EventProjections/event_projection_scenario_tests.cs b/src/DaemonTests/EventProjections/event_projection_scenario_tests.cs index 0a45c7b5a7..729be9c869 100644 --- a/src/DaemonTests/EventProjections/event_projection_scenario_tests.cs +++ b/src/DaemonTests/EventProjections/event_projection_scenario_tests.cs @@ -3,6 +3,7 @@ using JasperFx.Events.Projections; using Marten; using Marten.Events.Projections; +using JasperFx.Events.TestSupport; using Marten.Events.TestSupport; using Marten.Storage; using Marten.Testing.Documents; diff --git a/src/DaemonTests/EventProjections/projection_scenario_quality_tests.cs b/src/DaemonTests/EventProjections/projection_scenario_quality_tests.cs index 2136d45a8d..2987f71f20 100644 --- a/src/DaemonTests/EventProjections/projection_scenario_quality_tests.cs +++ b/src/DaemonTests/EventProjections/projection_scenario_quality_tests.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Threading.Tasks; using JasperFx.Events.Projections; +using JasperFx.Events.TestSupport; using Marten.Events.TestSupport; using Marten.Testing.Documents; using Marten.Testing.Harness; @@ -94,13 +95,13 @@ public async Task a_scenario_cannot_be_executed_twice() var scenario = new ProjectionScenario(theStore); scenario.Append(Guid.NewGuid(), new CreateUser { UserId = Guid.NewGuid(), UserName = "Once" }); - await scenario.Execute(TestContext.Current.CancellationToken); + await scenario.ExecuteAsync(TestContext.Current.CancellationToken); // The steps were consumed by the first run, so a second run would be a silent no-op. // It should be a loud failure instead. await Should.ThrowAsync(async () => { - await scenario.Execute(TestContext.Current.CancellationToken); + await scenario.ExecuteAsync(TestContext.Current.CancellationToken); }); } diff --git a/src/Marten/AdvancedOperations.cs b/src/Marten/AdvancedOperations.cs index 684651dc2b..26c673eb65 100644 --- a/src/Marten/AdvancedOperations.cs +++ b/src/Marten/AdvancedOperations.cs @@ -299,7 +299,7 @@ public Task EventProjectionScenario(Action configuration, Ca var scenario = new ProjectionScenario(_store); configuration(scenario); - return scenario.Execute(ct); + return scenario.ExecuteAsync(ct); } /// diff --git a/src/Marten/Events/TestSupport/ProjectionScenario.Assertions.cs b/src/Marten/Events/TestSupport/ProjectionScenario.Assertions.cs deleted file mode 100644 index e6724f69cb..0000000000 --- a/src/Marten/Events/TestSupport/ProjectionScenario.Assertions.cs +++ /dev/null @@ -1,133 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using JasperFx.Core.Reflection; - -namespace Marten.Events.TestSupport; - -public partial class ProjectionScenario -{ - /// - /// General hook to run - /// - /// - /// - public void AssertAgainstProjectedData(string description, Func assertions) - { - assertion(assertions).Description = description; - } - - /// - /// Verify that a document with the supplied id exists - /// - /// - /// Optional lambda to make additional assertions about the document state - /// The document type - public void DocumentShouldExist(string id, Action? assertions = null) where T : notnull - { - documentShouldExist(id, (session, ct) => session.LoadAsync(id, ct), assertions); - } - - /// - /// Verify that a document with the supplied id exists - /// - /// - /// Optional lambda to make additional assertions about the document state - /// The document type - public void DocumentShouldExist(long id, Action? assertions = null) where T : notnull - { - documentShouldExist(id, (session, ct) => session.LoadAsync(id, ct), assertions); - } - - /// - /// Verify that a document with the supplied id exists - /// - /// - /// Optional lambda to make additional assertions about the document state - /// The document type - public void DocumentShouldExist(int id, Action? assertions = null) where T : notnull - { - documentShouldExist(id, (session, ct) => session.LoadAsync(id, ct), assertions); - } - - /// - /// Verify that a document with the supplied id exists - /// - /// - /// Optional lambda to make additional assertions about the document state - /// The document type - public void DocumentShouldExist(Guid id, Action? assertions = null) where T : notnull - { - documentShouldExist(id, (session, ct) => session.LoadAsync(id, ct), assertions); - } - - /// - /// Asserts that a document with a given id has been deleted or does not exist - /// - /// The identity of the document - /// The document type - public void DocumentShouldNotExist(string id) where T : notnull - { - documentShouldNotExist(id, (session, ct) => session.LoadAsync(id, ct)); - } - - /// - /// Asserts that a document with a given id has been deleted or does not exist - /// - /// The identity of the document - /// The document type - public void DocumentShouldNotExist(long id) where T : notnull - { - documentShouldNotExist(id, (session, ct) => session.LoadAsync(id, ct)); - } - - /// - /// Asserts that a document with a given id has been deleted or does not exist - /// - /// The identity of the document - /// The document type - public void DocumentShouldNotExist(int id) where T : notnull - { - documentShouldNotExist(id, (session, ct) => session.LoadAsync(id, ct)); - } - - /// - /// Asserts that a document with a given id has been deleted or does not exist - /// - /// The identity of the document - /// The document type - public void DocumentShouldNotExist(Guid id) where T : notnull - { - documentShouldNotExist(id, (session, ct) => session.LoadAsync(id, ct)); - } - - private void documentShouldExist(object id, Func> load, - Action? assertions) where T : notnull - { - assertion(async (session, ct) => - { - var document = await load(session, ct).ConfigureAwait(false); - if (document == null) - { - throw new ProjectionScenarioAssertionException( - $"Document {typeof(T).FullNameInCode()} with id '{id}' does not exist"); - } - - assertions?.Invoke(document); - }).Description = $"Document {typeof(T).FullNameInCode()} with id '{id}' should exist"; - } - - private void documentShouldNotExist(object id, Func> load) - where T : notnull - { - assertion(async (session, ct) => - { - var document = await load(session, ct).ConfigureAwait(false); - if (document != null) - { - throw new ProjectionScenarioAssertionException( - $"Document {typeof(T).FullNameInCode()} with id '{id}' exists, but should not."); - } - }).Description = $"Document {typeof(T).FullNameInCode()} with id '{id}' should not exist or be deleted"; - } -} diff --git a/src/Marten/Events/TestSupport/ProjectionScenario.EventOperations.cs b/src/Marten/Events/TestSupport/ProjectionScenario.EventOperations.cs deleted file mode 100644 index bab5d600a8..0000000000 --- a/src/Marten/Events/TestSupport/ProjectionScenario.EventOperations.cs +++ /dev/null @@ -1,318 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using JasperFx.Core; -using JasperFx.Core.Reflection; -using JasperFx.Events; - -namespace Marten.Events.TestSupport; - -public partial class ProjectionScenario -{ - private static string describe(object[] events) - { - return events.Length > 3 ? "events" : events.Select(x => x.ToString()).Join(", "); - } - - /// - /// Queue appending events to an existing event stream in the scenario sequence - /// - /// The stream id - /// The events to append - public void Append(Guid stream, IEnumerable events) - { - Append(stream, events as object[] ?? events.ToArray()); - } - - /// - /// Queue appending events to an existing event stream in the scenario sequence - /// - /// The stream id - /// The events to append - public void Append(Guid stream, params object[] events) - { - action(e => e.Append(stream, events)).Description = $"Append({stream}, {describe(events)})"; - } - - /// - /// Queue appending events to an existing event stream in the scenario sequence - /// - /// The stream key - /// The events to append - public void Append(string stream, IEnumerable events) - { - Append(stream, events as object[] ?? events.ToArray()); - } - - /// - /// Queue appending events to an existing event stream in the scenario sequence - /// - /// The stream key - /// The events to append - public void Append(string stream, params object[] events) - { - action(e => e.Append(stream, events)).Description = $"Append(\"{stream}\", {describe(events)})"; - } - - /// - /// Queue appending events to an existing event stream with an expected version - /// in the scenario sequence - /// - /// The stream id - /// The expected stream version after appending - /// The events to append - public void Append(Guid stream, long expectedVersion, params object[] events) - { - action(e => e.Append(stream, expectedVersion, events)).Description = - $"Append({stream}, {expectedVersion}, {describe(events)})"; - } - - /// - /// Queue appending events to an existing event stream with an expected version - /// in the scenario sequence - /// - /// The stream key - /// The expected stream version after appending - /// The events to append - public void Append(string stream, long expectedVersion, IEnumerable events) - { - Append(stream, expectedVersion, events as object[] ?? events.ToArray()); - } - - /// - /// Queue appending events to an existing event stream with an expected version - /// in the scenario sequence - /// - /// The stream key - /// The expected stream version after appending - /// The events to append - public void Append(string stream, long expectedVersion, params object[] events) - { - action(e => e.Append(stream, expectedVersion, events)).Description = - $"Append(\"{stream}\", {expectedVersion}, {describe(events)})"; - } - - /// - /// Queue starting a new event stream in the scenario sequence - /// - /// The stream id - /// The initial events - /// The aggregate type for the new stream - public void StartStream(Guid id, params object[] events) where TAggregate : class - { - action(e => e.StartStream(id, events)).Description = - $"StartStream<{typeof(TAggregate).FullNameInCode()}>({id}, {describe(events)})"; - } - - /// - /// Queue starting a new event stream in the scenario sequence - /// - /// The aggregate type for the new stream - /// The stream id - /// The initial events - public void StartStream(Type aggregateType, Guid id, IEnumerable events) - { - StartStream(aggregateType, id, (events as object[] ?? events.ToArray())); - } - - /// - /// Queue starting a new event stream in the scenario sequence - /// - /// The aggregate type for the new stream - /// The stream id - /// The initial events - public void StartStream(Type aggregateType, Guid id, params object[] events) - { - action(e => e.StartStream(aggregateType, id, events)).Description = - $"StartStream({aggregateType.FullNameInCode()}, {id}, {describe(events)})"; - } - - /// - /// Queue starting a new event stream in the scenario sequence - /// - /// The stream key - /// The initial events - /// The aggregate type for the new stream - public void StartStream(string streamKey, IEnumerable events) - where TAggregate : class - { - StartStream(streamKey, events as object[] ?? events.ToArray()); - } - - /// - /// Queue starting a new event stream in the scenario sequence - /// - /// The stream key - /// The initial events - /// The aggregate type for the new stream - public void StartStream(string streamKey, params object[] events) where TAggregate : class - { - action(e => e.StartStream(streamKey, events)).Description = - $"StartStream<{typeof(TAggregate).FullNameInCode()}>(\"{streamKey}\", {describe(events)})"; - } - - /// - /// Queue starting a new event stream in the scenario sequence - /// - /// The aggregate type for the new stream - /// The stream key - /// The initial events - public void StartStream(Type aggregateType, string streamKey, IEnumerable events) - { - StartStream(aggregateType, streamKey, events as object[] ?? events.ToArray()); - } - - /// - /// Queue starting a new event stream in the scenario sequence - /// - /// The aggregate type for the new stream - /// The stream key - /// The initial events - public void StartStream(Type aggregateType, string streamKey, params object[] events) - { - action(e => e.StartStream(aggregateType, streamKey, events)).Description = - $"StartStream({aggregateType.FullNameInCode()}, \"{streamKey}\", {describe(events)})"; - } - - /// - /// Queue starting a new event stream in the scenario sequence - /// - /// The stream id - /// The initial events - public void StartStream(Guid id, IEnumerable events) - { - StartStream(id, events as object[] ?? events.ToArray()); - } - - /// - /// Queue starting a new event stream in the scenario sequence - /// - /// The stream id - /// The initial events - public void StartStream(Guid id, params object[] events) - { - action(e => e.StartStream(id, events)).Description = $"StartStream({id}, {describe(events)})"; - } - - /// - /// Queue starting a new event stream in the scenario sequence - /// - /// The stream key - /// The initial events - public void StartStream(string streamKey, IEnumerable events) - { - StartStream(streamKey, events as object[] ?? events.ToArray()); - } - - /// - /// Queue starting a new event stream in the scenario sequence - /// - /// The stream key - /// The initial events - public void StartStream(string streamKey, params object[] events) - { - action(e => e.StartStream(streamKey, events)).Description = - $"StartStream(\"{streamKey}\", {describe(events)})"; - } - - /// - /// Queue starting a new event stream with a newly generated stream id - /// in the scenario sequence - /// - /// The initial events - /// The aggregate type for the new stream - /// The generated id of the new stream - public Guid StartStream(IEnumerable events) where TAggregate : class - { - return StartStream(events as object[] ?? events.ToArray()); - } - - /// - /// Queue starting a new event stream with a newly generated stream id - /// in the scenario sequence - /// - /// The initial events - /// The aggregate type for the new stream - /// The generated id of the new stream - public Guid StartStream(params object[] events) where TAggregate : class - { - var streamId = Guid.NewGuid(); - action(e => e.StartStream(streamId, events)).Description = - $"StartStream<{typeof(TAggregate).FullNameInCode()}>({streamId}, {describe(events)})"; - - return streamId; - } - - /// - /// Queue starting a new event stream with a newly generated stream id - /// in the scenario sequence - /// - /// The aggregate type for the new stream - /// The initial events - /// The generated id of the new stream - public Guid StartStream(Type aggregateType, IEnumerable events) - { - return StartStream(aggregateType, events as object[] ?? events.ToArray()); - } - - /// - /// Queue starting a new event stream with a newly generated stream id - /// in the scenario sequence - /// - /// The aggregate type for the new stream - /// The initial events - /// The generated id of the new stream - public Guid StartStream(Type aggregateType, params object[] events) - { - var streamId = Guid.NewGuid(); - action(e => e.StartStream(aggregateType, streamId, events)).Description = - $"StartStream({aggregateType.FullNameInCode()}, {streamId}, {describe(events)})"; - - return streamId; - } - - /// - /// Queue starting a new event stream with a newly generated stream id - /// in the scenario sequence - /// - /// The initial events - /// The generated id of the new stream - public Guid StartStream(IEnumerable events) - { - return StartStream(events as object[] ?? events.ToArray()); - } - - /// - /// Queue starting a new event stream with a newly generated stream id - /// in the scenario sequence - /// - /// The initial events - /// The generated id of the new stream - public Guid StartStream(params object[] events) - { - var streamId = Guid.NewGuid(); - action(e => e.StartStream(streamId, events)).Description = - $"StartStream({streamId}, {describe(events)})"; - - return streamId; - } - - /// - /// Make any number of append event operations in the scenario sequence - /// - /// Descriptive explanation of the action in case of failures - /// - public void AppendEvents(string description, Action appendAction) - { - action(appendAction).Description = description; - } - - /// - /// Make any number of append event operations in the scenario sequence - /// - /// - public void AppendEvents(Action appendAction) - { - AppendEvents("Appending events...", appendAction); - } -} diff --git a/src/Marten/Events/TestSupport/ProjectionScenario.cs b/src/Marten/Events/TestSupport/ProjectionScenario.cs index 774d91fda9..56d4fa46de 100644 --- a/src/Marten/Events/TestSupport/ProjectionScenario.cs +++ b/src/Marten/Events/TestSupport/ProjectionScenario.cs @@ -1,181 +1,75 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using JasperFx.Core; +using JasperFx.Events; using JasperFx.Events.Daemon; -using Marten.Events.Daemon; +using JasperFx.Events.TestSupport; namespace Marten.Events.TestSupport; -public partial class ProjectionScenario +/// +/// Marten's implementation of the JasperFx.Events projection scenario test harness, +/// closing the generic session pair over / +/// . All scripting and execution behavior lives on the +/// base type; this class +/// only supplies the store-specific seam +/// +public class ProjectionScenario: JasperFx.Events.TestSupport.ProjectionScenario { - private readonly Queue _steps = new(); private readonly DocumentStore _store; - private bool _hasExecuted; internal ProjectionScenario(DocumentStore store) { _store = store; } - internal IProjectionDaemon? Daemon { get; private set; } - - internal ScenarioStep? NextStep => _steps.Count != 0 ? _steps.Peek() : null; - - internal IDocumentSession? Session { get; private set; } - - /// - /// The scenario deletes all existing event data plus the storage for every - /// registered projection before running. Set this to false to run the - /// scenario on top of whatever data already exists - /// - public bool DeleteExistingData { get; set; } = true; - - /// - /// Opt into applying this scenario to a specific tenant id in the - /// case of using multi-tenancy of any kind - /// - public string? TenantId { get; set; } - - /// - /// Maximum time the scenario waits for any asynchronous projections to - /// catch up after each batch of appended events. Default is 30 seconds - /// - public TimeSpan Timeout { get; set; } = 30.Seconds(); - - internal Task WaitForNonStaleData(CancellationToken ct = default) + protected override async Task DeleteExistingDataAsync(CancellationToken ct) { - if (Daemon == null) + await _store.Advanced.Clean.DeleteAllEventDataAsync(ct).ConfigureAwait(false); + foreach (var storageType in + _store.Options.Projections.All.SelectMany(x => x.Options.StorageTypes)) { - return Task.CompletedTask; + await _store.Advanced.Clean.DeleteDocumentsByTypeAsync(storageType, ct).ConfigureAwait(false); } - - return Daemon.WaitForNonStaleData(Timeout).WaitAsync(ct); } + protected override bool HasAnyAsyncProjections => _store.Options.Projections.HasAnyAsyncProjections(); - private ScenarioStep action(Action action) + protected override async ValueTask BuildDaemonAsync(string? tenantId) { - var step = new ScenarioAction(action); - _steps.Enqueue(step); - - return step; + return await _store.BuildProjectionDaemonAsync(tenantId).ConfigureAwait(false); } - private ScenarioStep assertion(Func check) + protected override IDocumentOperations OpenSession(string? tenantId) { - var step = new ScenarioAssertion(check); - _steps.Enqueue(step); - - return step; + return tenantId.IsNotEmpty() ? _store.LightweightSession(tenantId) : _store.LightweightSession(); } - internal async Task Execute(CancellationToken ct = default) + // No shared JasperFx interface declares SaveChangesAsync -- in Marten it lives on + // IDocumentSession, which every session handed out by OpenSession() actually is. + protected override Task SaveChangesAsync(IDocumentOperations session, CancellationToken ct) { - if (_hasExecuted) - { - throw new InvalidOperationException( - "This ProjectionScenario has already been executed and its steps have been consumed. Build and run a new scenario with DocumentStore.Advanced.EventProjectionScenario() instead"); - } - - _hasExecuted = true; - - if (DeleteExistingData) - { - await _store.Advanced.Clean.DeleteAllEventDataAsync(ct).ConfigureAwait(false); - foreach (var storageType in - _store.Options.Projections.All.SelectMany(x => x.Options.StorageTypes)) - await _store.Advanced.Clean.DeleteDocumentsByTypeAsync(storageType, ct).ConfigureAwait(false); - } - - if (_store.Options.Projections.HasAnyAsyncProjections()) - { - Daemon = await _store.BuildProjectionDaemonAsync(TenantId).ConfigureAwait(false); - await Daemon.StartAllAsync().ConfigureAwait(false); - } - - Session = TenantId.IsNotEmpty() ? _store.LightweightSession(TenantId) : _store.LightweightSession(); - - try - { - var exceptions = new List(); - var number = 0; - var descriptions = new List(); - var actionFailed = false; - - while (_steps.Any()) - { - number++; - var step = _steps.Dequeue(); - - try - { - await step.Execute(this, ct).ConfigureAwait(false); - descriptions.Add($"{number.ToString().PadLeft(3)}. {step.Description}"); - } - catch (Exception e) - { - descriptions.Add($"FAILED: {number.ToString().PadLeft(3)}. {step.Description}"); - descriptions.Add(e.ToString()); - exceptions.Add(e); - - // A failed action means every later step would run against a state nobody - // intended, so stop right here instead of piling up cascading noise. Failed - // assertions keep accumulating -- the state is still the intended one. - if (step is ScenarioAction) - { - actionFailed = true; - if (_steps.Count != 0) - { - descriptions.Add( - $"Skipped the remaining {_steps.Count} step(s) after the failed action"); - _steps.Clear(); - } - - break; - } - } - } + return ((IDocumentSession)session).SaveChangesAsync(ct); + } - // A ScenarioAction only flushes when the step AFTER it is an assertion, so whatever a - // trailing action queued is still sitting in the session -- and the finally below disposes - // that session without committing. An append with no assertion after it is still an append, - // and an arrange-only scenario should not be a silent no-op that passes. See #5126. - // - // Unconditional on purpose: SaveChangesAsync returns immediately when the unit of work is - // empty, and WaitForNonStaleData is already a no-op when no daemon is running. Skipped when - // an action failed -- the session may hold a partially built unit of work at that point. - if (!actionFailed) - { - try - { - await Session.SaveChangesAsync(ct).ConfigureAwait(false); - await WaitForNonStaleData(ct).ConfigureAwait(false); - } - catch (Exception e) - { - descriptions.Add("FAILED: committing the events queued by the final step"); - descriptions.Add(e.ToString()); - exceptions.Add(e); - } - } + protected override IEventOperations EventsFor(IDocumentOperations session) + { + return session.Events; + } - if (exceptions.Any()) - { - throw new ProjectionScenarioException(descriptions, exceptions); - } - } - finally + protected override Task LoadDocumentAsync(IQuerySession session, object id, CancellationToken ct) + where T : class + { + return id switch { - if (Daemon != null) - { - await Daemon.StopAllAsync().ConfigureAwait(false); - Daemon.SafeDispose(); - } - - Session?.SafeDispose(); - } + Guid guidId => session.LoadAsync(guidId, ct), + int intId => session.LoadAsync(intId, ct), + long longId => session.LoadAsync(longId, ct), + string stringId => session.LoadAsync(stringId, ct), + _ => throw new ArgumentOutOfRangeException(nameof(id), + $"Marten cannot load documents by an identity of type {id.GetType().FullName}") + }; } } diff --git a/src/Marten/Events/TestSupport/ProjectionScenarioAssertionException.cs b/src/Marten/Events/TestSupport/ProjectionScenarioAssertionException.cs deleted file mode 100644 index f1f49676df..0000000000 --- a/src/Marten/Events/TestSupport/ProjectionScenarioAssertionException.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Marten.Exceptions; - -namespace Marten.Events.TestSupport; - -/// -/// Thrown when a single ProjectionScenario assertion fails, e.g. a document that should -/// exist does not. Lets test code and tooling distinguish scenario assertion failures -/// from infrastructure failures inside the aggregated ProjectionScenarioException -/// -public class ProjectionScenarioAssertionException: MartenException -{ - public ProjectionScenarioAssertionException(string message): base(message) - { - } -} diff --git a/src/Marten/Events/TestSupport/ProjectionScenarioException.cs b/src/Marten/Events/TestSupport/ProjectionScenarioException.cs deleted file mode 100644 index fa1dc1ec1c..0000000000 --- a/src/Marten/Events/TestSupport/ProjectionScenarioException.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using JasperFx.Core; - -namespace Marten.Events.TestSupport; - -/// -/// Thrown when a ProjectionScenario fails -/// -public class ProjectionScenarioException: AggregateException -{ - public ProjectionScenarioException(List descriptions, List exceptions): base( - $"Event Projection Scenario Failure{Environment.NewLine}{descriptions.Join(Environment.NewLine)}", - exceptions) - { - } -} diff --git a/src/Marten/Events/TestSupport/ScenarioAction.cs b/src/Marten/Events/TestSupport/ScenarioAction.cs deleted file mode 100644 index 5d79a43823..0000000000 --- a/src/Marten/Events/TestSupport/ScenarioAction.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Marten.Events.TestSupport; - -internal class ScenarioAction: ScenarioStep -{ - private readonly Action _action; - - public ScenarioAction(Action action) - { - _action = action; - } - - public override async Task Execute(ProjectionScenario scenario, CancellationToken ct = default) - { - _action(scenario.Session!.Events); - - if (scenario.NextStep is ScenarioAssertion) - { - await scenario.Session!.SaveChangesAsync(ct).ConfigureAwait(false); - await scenario.WaitForNonStaleData(ct).ConfigureAwait(false); - } - } -} diff --git a/src/Marten/Events/TestSupport/ScenarioAssertion.cs b/src/Marten/Events/TestSupport/ScenarioAssertion.cs deleted file mode 100644 index 7a328525bb..0000000000 --- a/src/Marten/Events/TestSupport/ScenarioAssertion.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Marten.Events.TestSupport; - -internal class ScenarioAssertion: ScenarioStep -{ - private readonly Func _check; - - public ScenarioAssertion(Func check) - { - _check = check; - } - - public override Task Execute(ProjectionScenario scenario, CancellationToken ct = default) - { - return _check(scenario.Session!, ct); - } -} diff --git a/src/Marten/Events/TestSupport/ScenarioStep.cs b/src/Marten/Events/TestSupport/ScenarioStep.cs deleted file mode 100644 index 5788344be8..0000000000 --- a/src/Marten/Events/TestSupport/ScenarioStep.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; - -namespace Marten.Events.TestSupport; - -internal abstract class ScenarioStep -{ - public string Description { get; set; } = string.Empty; - - public abstract Task Execute(ProjectionScenario scenario, CancellationToken ct = default); -}