diff --git a/.github/workflows/release-preview.yml b/.github/workflows/release-preview.yml
index 6835c7b..4b73b27 100644
--- a/.github/workflows/release-preview.yml
+++ b/.github/workflows/release-preview.yml
@@ -28,10 +28,10 @@ jobs:
- name: ⚙️ Setup GIT versioning
uses: dotnet/nbgv@v0.4.0
- - name: ⚙️ Setup dotnet 7.0.x
+ - name: ⚙️ Setup dotnet 9.0.x
uses: actions/setup-dotnet@v1
with:
- dotnet-version: '7.0.x'
+ dotnet-version: '9.0.x'
- name: 🛠️ Building library in release mode
run: dotnet pack -c Release -o ${GITHUB_WORKSPACE}/packages -p:ContinuousIntegrationBuild=true -p:publicrelease=true
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index cf90c5e..f1d686a 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -59,10 +59,10 @@ jobs:
with:
setAllVars: true
- - name: ⚙️ Setup dotnet 7.0.x
+ - name: ⚙️ Setup dotnet 9.0.x
uses: actions/setup-dotnet@v1
with:
- dotnet-version: '7.0.x'
+ dotnet-version: '9.0.x'
- name: 🛠️ Update changelog
uses: thomaseizinger/keep-a-changelog-new-release@1.2.1
diff --git a/.github/workflows/verification.yml b/.github/workflows/verification.yml
index c1228c3..47f3240 100644
--- a/.github/workflows/verification.yml
+++ b/.github/workflows/verification.yml
@@ -33,10 +33,10 @@ jobs:
with:
setAllVars: true
- - name: ⚙️ Setup dotnet 7.0.x
+ - name: ⚙️ Setup dotnet 9.0.x
uses: actions/setup-dotnet@v1
with:
- dotnet-version: '7.0.x'
+ dotnet-version: '9.0.x'
- name: 🛠️ Building libraries in release mode
run: dotnet build -c release -p:ContinuousIntegrationBuild=true
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6a1d26d..1169292 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
+### Added
+
+- Implement `IEventStoreManagementClient.DeleteStreamAsync` using the newly released `DeleteAllItemsByPartitionKeyStreamAsync` method in the Cosmos SDK.
+- Extend `CommandContext` with the current `StreamVersion` of the stream.
+
## [1.13.3] - 2024-04-21
### Added
@@ -187,4 +192,4 @@ services.AddEventStore(builder =>
[1.3.3]: https://github.com/atc-net/atc-cosmos-eventstore/compare/v1.2.9...v1.3.3
-[1.2.9]: https://github.com/atc-net/atc-cosmos-eventstore/compare/v1.1.3...v1.2.9
+[1.2.9]: https://github.com/atc-net/atc-cosmos-eventstore/compare/v1.1.3...v1.2.9
\ No newline at end of file
diff --git a/Directory.Build.props b/Directory.Build.props
index 5a094fb..15612a6 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -27,7 +27,7 @@
- AllEnabledByDefault
+ Default
true
latest
true
diff --git a/sample/.editorconfig b/sample/.editorconfig
deleted file mode 100644
index d6c0e20..0000000
--- a/sample/.editorconfig
+++ /dev/null
@@ -1,80 +0,0 @@
-# ATC coding rules - https://github.com/atc-net/atc-coding-rules
-# Version: 1.0.0
-# Updated: 04-12-2020
-# Location: Sample
-# Inspired by: https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/code-style-rule-options
-
-##########################################
-# Code Analyzers Rules
-##########################################
-[*.{cs,csx,cake}]
-
-# AsyncFixer
-# http://www.asyncfixer.com
-
-
-# Asyncify
-# https://github.com/hvanbakel/Asyncify-CSharp
-
-
-# Meziantou
-# https://www.meziantou.net/enforcing-asynchronous-code-good-practices-using-a-roslyn-analyzer.htm
-
-# Microsoft - Code Analysis
-# https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/
-
-
-# Microsoft - FxCop
-# https://github.com/dotnet/roslyn-analyzers
-
-
-# Microsoft - Threading
-# https://github.com/microsoft/vs-threading/blob/master/doc/analyzers/index.md
-
-
-# SecurityCodeScan
-# https://security-code-scan.github.io/
-
-
-# StyleCop
-# https://github.com/DotNetAnalyzers/StyleCopAnalyzers
-
-
-##########################################
-# Custom - Code Analyzers Rules
-##########################################
-
-# AsyncFixer
-# http://www.asyncfixer.com
-
-
-# Asyncify
-# https://github.com/hvanbakel/Asyncify-CSharp
-
-
-# Meziantou
-# https://www.meziantou.net/enforcing-asynchronous-code-good-practices-using-a-roslyn-analyzer.htm
-
-# Microsoft - Code Analysis
-# https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/
-
-
-# Microsoft - FxCop
-# https://github.com/dotnet/roslyn-analyzers
-
-
-# Microsoft - Threading
-# https://github.com/microsoft/vs-threading/blob/master/doc/analyzers/index.md
-
-
-# SecurityCodeScan
-# https://security-code-scan.github.io/
-
-
-# StyleCop
-# https://github.com/DotNetAnalyzers/StyleCopAnalyzers
-
-
-##########################################
-# Custom - Code Analyzers Rules
-##########################################
\ No newline at end of file
diff --git a/sample/GettingStarted/Commands/CreateCommands.cs b/sample/GettingStarted/Commands/CreateCommands.cs
new file mode 100644
index 0000000..672e3fb
--- /dev/null
+++ b/sample/GettingStarted/Commands/CreateCommands.cs
@@ -0,0 +1,31 @@
+using Atc.Cosmos.EventStore.Cqrs;
+
+namespace GettingStarted;
+
+public record CreateCommand(string Id, string Name, string Address)
+ : CommandBase(new SampleEventStreamId(Id));
+
+public class CreateCommandHandler :
+ ICommandHandler,
+ IConsumeEvent
+{
+ private bool created;
+
+ public void Consume(CreateCommand evt, EventMetadata metadata)
+ {
+ this.created = true;
+ }
+
+ public ValueTask ExecuteAsync(
+ CreateCommand command,
+ ICommandContext context,
+ CancellationToken cancellationToken)
+ {
+ if (!created)
+ {
+ context.AddEvent(new AddedEvent(command.Name, command.Address));
+ }
+
+ return ValueTask.CompletedTask;
+ }
+}
\ No newline at end of file
diff --git a/sample/GettingStarted/Commands/DeleteCommand.cs b/sample/GettingStarted/Commands/DeleteCommand.cs
new file mode 100644
index 0000000..b812777
--- /dev/null
+++ b/sample/GettingStarted/Commands/DeleteCommand.cs
@@ -0,0 +1,44 @@
+using Atc.Cosmos.EventStore.Cqrs;
+
+namespace GettingStarted;
+
+public record DeleteCommand(string Id, string Reason)
+ : CommandBase(new SampleEventStreamId(Id));
+
+public class DeleteCommandHandler :
+ ICommandHandler,
+ IConsumeEvent,
+ IConsumeEvent
+{
+ private bool created;
+ private bool deleted;
+
+ public void Consume(AddedEvent evt, EventMetadata metadata)
+ {
+ this.created = true;
+ }
+
+ public void Consume(DeletedEvent evt, EventMetadata metadata)
+ {
+ this.deleted = true;
+ }
+
+ public ValueTask ExecuteAsync(
+ DeleteCommand command,
+ ICommandContext context,
+ CancellationToken cancellationToken)
+ {
+ if (!created)
+ {
+ throw new InvalidOperationException("Cannot delete non-existing entity.");
+ }
+
+ if (deleted)
+ {
+ throw new InvalidOperationException("Already deleted.");
+ }
+
+ context.AddEvent(new DeletedEvent(command.Reason));
+ return ValueTask.CompletedTask;
+ }
+}
\ No newline at end of file
diff --git a/sample/GettingStarted/Commands/UpdateNameCommands.cs b/sample/GettingStarted/Commands/UpdateNameCommands.cs
new file mode 100644
index 0000000..67feac3
--- /dev/null
+++ b/sample/GettingStarted/Commands/UpdateNameCommands.cs
@@ -0,0 +1,44 @@
+using Atc.Cosmos.EventStore.Cqrs;
+
+namespace GettingStarted;
+
+public record UpdateNameCommand(string Id, string Name)
+ : CommandBase(new SampleEventStreamId(Id));
+
+public class UpdateNameCommandHandler :
+ ICommandHandler,
+ IConsumeEvent,
+ IConsumeEvent
+{
+ private bool created;
+ private string? currentName;
+
+ public void Consume(AddedEvent evt, EventMetadata metadata)
+ {
+ created = true;
+ currentName = evt.Name;
+ }
+
+ public void Consume(NameChangedEvent evt, EventMetadata metadata)
+ {
+ currentName = evt.NewName;
+ }
+
+ public ValueTask ExecuteAsync(
+ UpdateNameCommand command,
+ ICommandContext context,
+ CancellationToken cancellationToken)
+ {
+ if (!created)
+ {
+ throw new InvalidOperationException("Cannot change name on non-existing entity.");
+ }
+
+ if (currentName != command.Name)
+ {
+ context.AddEvent(new NameChangedEvent(currentName!, command.Name));
+ }
+
+ return ValueTask.CompletedTask;
+ }
+}
\ No newline at end of file
diff --git a/sample/GettingStarted/ConsoleHostedService.cs b/sample/GettingStarted/ConsoleHostedService.cs
new file mode 100644
index 0000000..0341bae
--- /dev/null
+++ b/sample/GettingStarted/ConsoleHostedService.cs
@@ -0,0 +1,44 @@
+using Atc.Cosmos.EventStore.Cqrs;
+using Microsoft.Extensions.Hosting;
+
+namespace GettingStarted;
+
+public class ConsoleHostedService(ICommandProcessorFactory commandProcessorFactory) : IHostedService
+{
+ public async Task StartAsync(CancellationToken cancellationToken)
+ {
+ var id = Guid.NewGuid().ToString("N");
+
+ await commandProcessorFactory
+ .Create()
+ .ExecuteAsync(
+ new CreateCommand(id, "First", "Address 1"),
+ cancellationToken);
+
+ await commandProcessorFactory
+ .Create()
+ .ExecuteAsync(
+ new UpdateNameCommand(id, "Second"),
+ cancellationToken);
+
+ await commandProcessorFactory
+ .Create()
+ .ExecuteAsync(
+ new UpdateNameCommand(id, "Third"),
+ cancellationToken);
+
+ await commandProcessorFactory
+ .Create()
+ .ExecuteAsync(
+ new DeleteCommand(id, "Deleted"),
+ cancellationToken);
+
+ await commandProcessorFactory
+ .Create()
+ .ExecuteAsync(
+ new DeleteCommand(id, "Deleted"),
+ cancellationToken);
+ }
+
+ public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
+}
\ No newline at end of file
diff --git a/sample/GettingStarted/Events/AddedEvent.cs b/sample/GettingStarted/Events/AddedEvent.cs
new file mode 100644
index 0000000..0f7fdc4
--- /dev/null
+++ b/sample/GettingStarted/Events/AddedEvent.cs
@@ -0,0 +1,6 @@
+using Atc.Cosmos.EventStore.Cqrs;
+
+namespace GettingStarted;
+
+[StreamEvent("added-event:v1")]
+public record AddedEvent(string Name, string Address);
\ No newline at end of file
diff --git a/sample/GettingStarted/Events/AddressChangedEvent.cs b/sample/GettingStarted/Events/AddressChangedEvent.cs
new file mode 100644
index 0000000..3840e1f
--- /dev/null
+++ b/sample/GettingStarted/Events/AddressChangedEvent.cs
@@ -0,0 +1,6 @@
+using Atc.Cosmos.EventStore.Cqrs;
+
+namespace GettingStarted;
+
+[StreamEvent("address-changed-event:v1")]
+public record AddressChangedEvent(string OldAddress, string NewAddress);
\ No newline at end of file
diff --git a/sample/GettingStarted/Events/DeletedEvent.cs b/sample/GettingStarted/Events/DeletedEvent.cs
new file mode 100644
index 0000000..f765623
--- /dev/null
+++ b/sample/GettingStarted/Events/DeletedEvent.cs
@@ -0,0 +1,6 @@
+using Atc.Cosmos.EventStore.Cqrs;
+
+namespace GettingStarted;
+
+[StreamEvent("deleted-event:v1")]
+public record DeletedEvent(string Reason);
\ No newline at end of file
diff --git a/sample/GettingStarted/Events/NameChangedEvent.cs b/sample/GettingStarted/Events/NameChangedEvent.cs
new file mode 100644
index 0000000..2ecbddb
--- /dev/null
+++ b/sample/GettingStarted/Events/NameChangedEvent.cs
@@ -0,0 +1,6 @@
+using Atc.Cosmos.EventStore.Cqrs;
+
+namespace GettingStarted;
+
+[StreamEvent("name-changed-event:v1")]
+public record NameChangedEvent(string OldName, string NewName);
\ No newline at end of file
diff --git a/sample/GettingStarted/GettingStarted.csproj b/sample/GettingStarted/GettingStarted.csproj
new file mode 100644
index 0000000..845cc80
--- /dev/null
+++ b/sample/GettingStarted/GettingStarted.csproj
@@ -0,0 +1,17 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+ latest
+
+
+
+
+
+
+
+
+
diff --git a/sample/GettingStarted/Program.cs b/sample/GettingStarted/Program.cs
new file mode 100644
index 0000000..6e7b4d8
--- /dev/null
+++ b/sample/GettingStarted/Program.cs
@@ -0,0 +1,62 @@
+using Atc.Cosmos;
+using Atc.Cosmos.EventStore;
+using GettingStarted;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Atc.Cosmos.Internal;
+using GettingStarted.Storage;
+using Microsoft.Extensions.Options;
+
+void ConfigureServices(IServiceCollection services)
+{
+ services.ConfigureOptions();
+ services.ConfigureCosmos(builder =>
+ {
+ builder.AddContainer(ContainerInitializer.Name);
+ builder.UseHostedService();
+ });
+
+ services.ConfigureOptions();
+ services.AddEventStore(
+ builder =>
+ {
+ builder.UseCosmosDb();
+ builder.UseEvents(catalogBuilder => catalogBuilder.FromAssembly());
+ builder.UseCQRS(
+ c =>
+ {
+ c.AddInitialization(
+ 4000,
+ serviceProvider => serviceProvider
+ .GetRequiredService()
+ .InitializeAsync(CancellationToken.None));
+
+ c.AddCommandsFromAssembly();
+ c.AddProjectionJob(nameof(SampleProjection));
+ });
+ });
+
+ services.AddHostedService();
+}
+
+await Host.CreateDefaultBuilder()
+ .ConfigureServices(ConfigureServices)
+ .RunConsoleAsync();
+
+public class ConfigureCosmosOptions : IConfigureOptions
+{
+ public void Configure(CosmosOptions options)
+ {
+ options.UseCosmosEmulator();
+ options.DatabaseName = "CQRS";
+ }
+}
+
+public class ConfigureEventStoreOptions : IConfigureOptions
+{
+ public void Configure(EventStoreClientOptions options)
+ {
+ options.UseCosmosEmulator();
+ options.EventStoreDatabaseId = "CQRS";
+ }
+}
\ No newline at end of file
diff --git a/sample/GettingStarted/Projections/ContainerInitializer.cs b/sample/GettingStarted/Projections/ContainerInitializer.cs
new file mode 100644
index 0000000..d68cf43
--- /dev/null
+++ b/sample/GettingStarted/Projections/ContainerInitializer.cs
@@ -0,0 +1,25 @@
+using Atc.Cosmos;
+using Microsoft.Azure.Cosmos;
+
+namespace GettingStarted.Storage;
+
+public class ContainerInitializer : ICosmosContainerInitializer
+{
+ public const string Name = "read-models";
+
+ public Task InitializeAsync(Database database, CancellationToken cancellationToken)
+ {
+ var options = new ContainerProperties
+ {
+ IndexingPolicy = new IndexingPolicy
+ {
+ Automatic = true,
+ IndexingMode = IndexingMode.Consistent,
+ },
+ PartitionKeyPath = "/pk",
+ Id = Name,
+ };
+
+ return database.CreateContainerIfNotExistsAsync(options, cancellationToken: cancellationToken);
+ }
+}
\ No newline at end of file
diff --git a/sample/GettingStarted/Projections/SampleProjection.cs b/sample/GettingStarted/Projections/SampleProjection.cs
new file mode 100644
index 0000000..789bbd0
--- /dev/null
+++ b/sample/GettingStarted/Projections/SampleProjection.cs
@@ -0,0 +1,66 @@
+using Atc.Cosmos;
+using Atc.Cosmos.EventStore.Cqrs;
+
+namespace GettingStarted.Storage;
+
+[ProjectionFilter(SampleEventStreamId.FilterIncludeAllEvents)]
+public class SampleProjection(
+ ICosmosReader reader,
+ ICosmosWriter writer) :
+ IProjection,
+ IConsumeEvent,
+ IConsumeEvent,
+ IConsumeEvent,
+ IConsumeEvent
+{
+ private SampleReadModel view = null!;
+ private bool deleted = false;
+
+ public Task FailedAsync(
+ Exception exception,
+ CancellationToken cancellationToken) =>
+ Task.FromResult(ProjectionAction.Continue);
+
+ public async Task InitializeAsync(
+ EventStreamId id,
+ CancellationToken cancellationToken)
+ {
+ var streamId = new SampleEventStreamId(id);
+ view = await reader.FindAsync(
+ streamId.Id,
+ streamId.Id,
+ cancellationToken) ??
+ new SampleReadModel
+ {
+ Id = streamId.Id,
+ };
+ }
+
+ public Task CompleteAsync(
+ CancellationToken cancellationToken) =>
+ deleted
+ ? writer.TryDeleteAsync(view!.Id, view!.PartitionKey, cancellationToken)
+ : writer.WriteAsync(view, cancellationToken);
+
+ public void Consume(AddedEvent evt, EventMetadata metadata)
+ {
+ view.Name = evt.Name;
+ view.Address = evt.Address;
+ deleted = false;
+ }
+
+ public void Consume(NameChangedEvent evt, EventMetadata metadata)
+ {
+ view.Name = evt.NewName;
+ }
+
+ public void Consume(AddressChangedEvent evt, EventMetadata metadata)
+ {
+ view.Address = evt.NewAddress;
+ }
+
+ public void Consume(DeletedEvent evt, EventMetadata metadata)
+ {
+ deleted = true;
+ }
+}
\ No newline at end of file
diff --git a/sample/GettingStarted/Projections/SampleReadModel.cs b/sample/GettingStarted/Projections/SampleReadModel.cs
new file mode 100644
index 0000000..1d8dee4
--- /dev/null
+++ b/sample/GettingStarted/Projections/SampleReadModel.cs
@@ -0,0 +1,21 @@
+using System.Text.Json.Serialization;
+using Atc.Cosmos;
+
+namespace GettingStarted.Storage;
+
+public class SampleReadModel : CosmosResource
+{
+ [JsonPropertyName("id")]
+ public string Id { get; set; }
+
+ [JsonPropertyName("pk")]
+ public string PartitionKey { get; set; }
+
+ public string Name { get; set; }
+
+ public string Address { get; set; }
+
+ protected override string GetDocumentId() => Id;
+
+ protected override string GetPartitionKey() => PartitionKey;
+}
\ No newline at end of file
diff --git a/sample/GettingStarted/SampleEventStreamId.cs b/sample/GettingStarted/SampleEventStreamId.cs
new file mode 100644
index 0000000..0ffa25a
--- /dev/null
+++ b/sample/GettingStarted/SampleEventStreamId.cs
@@ -0,0 +1,32 @@
+using Atc.Cosmos.EventStore.Cqrs;
+
+namespace GettingStarted;
+
+public sealed class SampleEventStreamId : EventStreamId, IEquatable
+{
+ private const string TypeName = "sample";
+ public const string FilterIncludeAllEvents = TypeName + ".*";
+
+ public SampleEventStreamId(string id)
+ : base(TypeName, id)
+ {
+ Id = id;
+ }
+
+ public SampleEventStreamId(EventStreamId id)
+ : base(id.Parts.ToArray())
+ {
+ Id = id.Parts[1];
+ }
+
+ public string Id { get; }
+
+ public override bool Equals(object? obj)
+ => Equals(obj as SampleEventStreamId);
+
+ public bool Equals(SampleEventStreamId? other)
+ => other != null && Value == other.Value;
+
+ public override int GetHashCode()
+ => HashCode.Combine(Value);
+}
\ No newline at end of file
diff --git a/sample/directory.build.props b/sample/directory.build.props
deleted file mode 100644
index 6f820a0..0000000
--- a/sample/directory.build.props
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
- false
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/sample/directory.build.targets b/sample/directory.build.targets
deleted file mode 100644
index 467d7af..0000000
--- a/sample/directory.build.targets
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
- latest
- $(NoWarn);1591
-
-
- true
- bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml
-
-
- full
- true
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/Atc.Cosmos.EventStore.Cqrs/Commands/CommandContext.cs b/src/Atc.Cosmos.EventStore.Cqrs/Commands/CommandContext.cs
index 2f39a51..24dc2f0 100644
--- a/src/Atc.Cosmos.EventStore.Cqrs/Commands/CommandContext.cs
+++ b/src/Atc.Cosmos.EventStore.Cqrs/Commands/CommandContext.cs
@@ -5,10 +5,17 @@ namespace Atc.Cosmos.EventStore.Cqrs.Commands;
internal class CommandContext : ICommandContext, ICommandContextInspector
{
+ public StreamVersion StreamVersion { get; }
+
public const int EventLimit = 10;
private readonly List
@@ -16,14 +18,14 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/src/Atc.Cosmos.EventStore/Cosmos/CosmosDeleter.cs b/src/Atc.Cosmos.EventStore/Cosmos/CosmosDeleter.cs
new file mode 100644
index 0000000..a424e2d
--- /dev/null
+++ b/src/Atc.Cosmos.EventStore/Cosmos/CosmosDeleter.cs
@@ -0,0 +1,25 @@
+using Atc.Cosmos.EventStore.Streams;
+using Microsoft.Azure.Cosmos;
+
+namespace Atc.Cosmos.EventStore.Cosmos;
+
+internal class CosmosDeleter : IStreamDeleter
+{
+ private readonly IEventStoreContainerProvider containerProvider;
+
+ public CosmosDeleter(IEventStoreContainerProvider containerProvider)
+ {
+ this.containerProvider = containerProvider;
+ }
+
+ public async Task DeleteAsync(
+ StreamId streamId,
+ CancellationToken cancellationToken)
+ {
+ var pk = new PartitionKey(streamId.Value);
+ var container = containerProvider.GetStreamContainer();
+ var response = await container.DeleteAllItemsByPartitionKeyStreamAsync(pk, null, cancellationToken);
+
+ response.EnsureSuccessStatusCode();
+ }
+}
\ No newline at end of file
diff --git a/src/Atc.Cosmos.EventStore/DependencyInjection/EventStoreOptionsBuilder.cs b/src/Atc.Cosmos.EventStore/DependencyInjection/EventStoreOptionsBuilder.cs
index dee8590..e157232 100644
--- a/src/Atc.Cosmos.EventStore/DependencyInjection/EventStoreOptionsBuilder.cs
+++ b/src/Atc.Cosmos.EventStore/DependencyInjection/EventStoreOptionsBuilder.cs
@@ -33,6 +33,7 @@ public EventStoreOptionsBuilder UseCosmosDb(
Services.TryAddSingleton();
Services.TryAddSingleton();
Services.TryAddSingleton();
+ Services.TryAddSingleton();
Services.TryAddSingleton();
Services.TryAddSingleton();
@@ -74,6 +75,7 @@ internal EventStoreOptionsBuilder UseInMemoryDb()
Services.TryAddSingleton(s => s.GetRequiredService());
Services.TryAddSingleton(s => s.GetRequiredService());
Services.TryAddSingleton(s => s.GetRequiredService());
+ Services.TryAddSingleton(s => s.GetRequiredService());
Services.TryAddSingleton(s => s.GetRequiredService());
Services.TryAddSingleton(s => s.GetRequiredService());
Services.TryAddSingleton(s => s.GetRequiredService());
diff --git a/src/Atc.Cosmos.EventStore/EventStoreManagementClient.cs b/src/Atc.Cosmos.EventStore/EventStoreManagementClient.cs
index 7c59610..f6dcc8a 100644
--- a/src/Atc.Cosmos.EventStore/EventStoreManagementClient.cs
+++ b/src/Atc.Cosmos.EventStore/EventStoreManagementClient.cs
@@ -1,11 +1,20 @@
+using Atc.Cosmos.EventStore.Streams;
+
namespace Atc.Cosmos.EventStore;
internal class EventStoreManagementClient : IEventStoreManagementClient
{
+ private readonly IStreamDeleter streamDeleter;
+
+ public EventStoreManagementClient(IStreamDeleter streamDeleter)
+ {
+ this.streamDeleter = streamDeleter;
+ }
+
public Task DeleteStreamAsync(
StreamId streamId,
CancellationToken cancellationToken = default)
- => throw new NotImplementedException();
+ => streamDeleter.DeleteAsync(streamId, cancellationToken);
public Task PurgeStreamAsync(
StreamId streamId,
diff --git a/src/Atc.Cosmos.EventStore/IEventStoreManagementClient.cs b/src/Atc.Cosmos.EventStore/IEventStoreManagementClient.cs
index d615184..8b4d022 100644
--- a/src/Atc.Cosmos.EventStore/IEventStoreManagementClient.cs
+++ b/src/Atc.Cosmos.EventStore/IEventStoreManagementClient.cs
@@ -39,7 +39,7 @@ Task PurgeStreamAsync(
CancellationToken cancellationToken = default);
///
- /// Deletes an entire stream and it's index.
+ /// Deletes an entire stream.
///
/// Attempting to write to a deleted stream will create a new empty stream.
/// Id of the event stream to delete.
diff --git a/src/Atc.Cosmos.EventStore/InMemory/InMemoryStore.cs b/src/Atc.Cosmos.EventStore/InMemory/InMemoryStore.cs
index 9ea0de1..4f6376a 100644
--- a/src/Atc.Cosmos.EventStore/InMemory/InMemoryStore.cs
+++ b/src/Atc.Cosmos.EventStore/InMemory/InMemoryStore.cs
@@ -9,6 +9,7 @@ internal class InMemoryStore :
IStreamMetadataReader,
IStreamIterator,
IStreamBatchWriter,
+ IStreamDeleter,
IStreamSubscriptionFactory,
IStreamSubscriptionRemover,
IStreamIndexReader,
@@ -69,6 +70,9 @@ Task IStreamBatchWriter.WriteAsync(
CancellationToken cancellationToken)
=> throw new NotImplementedException();
+ public Task DeleteAsync(StreamId streamId, CancellationToken cancellationToken)
+ => throw new NotImplementedException();
+
public Task WriteAsync(
string name,
StreamId streamId,
diff --git a/src/Atc.Cosmos.EventStore/Streams/IStreamDeleter.cs b/src/Atc.Cosmos.EventStore/Streams/IStreamDeleter.cs
new file mode 100644
index 0000000..6e427c9
--- /dev/null
+++ b/src/Atc.Cosmos.EventStore/Streams/IStreamDeleter.cs
@@ -0,0 +1,8 @@
+namespace Atc.Cosmos.EventStore.Streams;
+
+internal interface IStreamDeleter
+{
+ Task DeleteAsync(
+ StreamId streamId,
+ CancellationToken cancellationToken);
+}
\ No newline at end of file
diff --git a/test/Atc.Cosmos.EventStore.Cqrs.Tests/Atc.Cosmos.EventStore.Cqrs.Tests.csproj b/test/Atc.Cosmos.EventStore.Cqrs.Tests/Atc.Cosmos.EventStore.Cqrs.Tests.csproj
index 344165f..e77b84c 100644
--- a/test/Atc.Cosmos.EventStore.Cqrs.Tests/Atc.Cosmos.EventStore.Cqrs.Tests.csproj
+++ b/test/Atc.Cosmos.EventStore.Cqrs.Tests/Atc.Cosmos.EventStore.Cqrs.Tests.csproj
@@ -1,20 +1,20 @@
- net7.0
+ net9.0
false
-
-
-
-
-
+
+
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/test/Atc.Cosmos.EventStore.Cqrs.Tests/Commands/CommandProcessorTests.cs b/test/Atc.Cosmos.EventStore.Cqrs.Tests/Commands/CommandProcessorTests.cs
new file mode 100644
index 0000000..5c835d3
--- /dev/null
+++ b/test/Atc.Cosmos.EventStore.Cqrs.Tests/Commands/CommandProcessorTests.cs
@@ -0,0 +1,180 @@
+using System.Collections.ObjectModel;
+using Atc.Cosmos.EventStore.Cqrs.Commands;
+using Atc.Cosmos.EventStore.Cqrs.Tests.Mocks;
+using Atc.Test;
+using AutoFixture.Xunit2;
+using FluentAssertions;
+using NSubstitute;
+using Xunit;
+
+namespace Atc.Cosmos.EventStore.Cqrs.Tests.Commands;
+
+public class CommandProcessorTests
+{
+ [Theory, AutoNSubstituteData]
+ internal async Task Should_Exeute_State_Projector(
+ [Frozen] ICommandHandlerFactory commandHandlerFactory,
+ [Frozen] IStateProjector stateProjector,
+ CommandProcessor sut,
+ MockCommand command,
+ ICommandHandler handler,
+ Atc.Cosmos.EventStore.Cqrs.Commands.StreamState streamState,
+ CancellationToken cancellationToken)
+ {
+ commandHandlerFactory.Create().Returns(handler);
+ stateProjector.ProjectAsync(command, handler, cancellationToken).Returns(streamState);
+
+ await sut.ExecuteAsync(command, cancellationToken);
+
+ await stateProjector.Received(1).ProjectAsync(command, handler, cancellationToken);
+ }
+
+ [Theory, AutoNSubstituteData]
+ internal async Task Should_Execute_Command(
+ [Frozen] ICommandHandlerFactory commandHandlerFactory,
+ [Frozen] IStateProjector stateProjector,
+ CommandProcessor sut,
+ MockCommand command,
+ ICommandHandler handler,
+ Atc.Cosmos.EventStore.Cqrs.Commands.StreamState streamState,
+ CancellationToken cancellationToken)
+ {
+ commandHandlerFactory.Create().Returns(handler);
+ stateProjector.ProjectAsync(command, handler, cancellationToken).Returns(streamState);
+
+ await sut.ExecuteAsync(command, cancellationToken);
+
+ await handler.Received(1).ExecuteAsync(command, Arg.Any(), cancellationToken);
+ }
+
+ [Theory, AutoNSubstituteData]
+ internal async Task Should_Set_Command_Context_StreamVersion(
+ [Frozen] ICommandHandlerFactory commandHandlerFactory,
+ [Frozen] IStateProjector stateProjector,
+ CommandProcessor sut,
+ MockCommand command,
+ ICommandHandler handler,
+ Atc.Cosmos.EventStore.Cqrs.Commands.StreamState streamState,
+ CancellationToken cancellationToken)
+ {
+ commandHandlerFactory.Create().Returns(handler);
+ stateProjector.ProjectAsync(command, handler, cancellationToken).Returns(streamState);
+
+ await sut.ExecuteAsync(command, cancellationToken);
+
+ var commandContext = handler.ReceivedCallWithArgument();
+ commandContext.StreamVersion.Should().Be(streamState.Version);
+ }
+
+ [Theory, AutoNSubstituteData]
+ internal async Task Should_Return_NotModified_When_Command_Emits_No_Events(
+ [Frozen] ICommandHandlerFactory commandHandlerFactory,
+ [Frozen] IStateProjector stateProjector,
+ CommandProcessor sut,
+ MockCommand command,
+ MockCommandHandler handler,
+ Atc.Cosmos.EventStore.Cqrs.Commands.StreamState streamState,
+ CancellationToken cancellationToken)
+ {
+ commandHandlerFactory.Create().Returns(handler);
+ stateProjector.ProjectAsync(command, handler, cancellationToken).Returns(streamState);
+
+ var result = await sut.ExecuteAsync(command, cancellationToken);
+
+ result.Result.Should().Be(ResultType.NotModified);
+ }
+
+ [Theory, AutoNSubstituteData]
+ internal async Task Should_Write_ResposeObject_To_CommandResult_When_Command_Emits_No_Events(
+ [Frozen] ICommandHandlerFactory commandHandlerFactory,
+ [Frozen] IStateProjector stateProjector,
+ CommandProcessor sut,
+ MockCommand command,
+ MockCommandHandler handler,
+ object responseObject,
+ Atc.Cosmos.EventStore.Cqrs.Commands.StreamState streamState,
+ CancellationToken cancellationToken)
+ {
+ commandHandlerFactory.Create().Returns(handler);
+ stateProjector.ProjectAsync(command, handler, cancellationToken).Returns(streamState);
+ handler.ResponseObject = responseObject;
+
+ var result = await sut.ExecuteAsync(command, cancellationToken);
+
+ result.Response.Should().Be(responseObject);
+ }
+
+ [Theory, AutoNSubstituteData]
+ internal async Task Should_Call_StateWriter_With_Events__When_Command_Emits_Events(
+ [Frozen] ICommandHandlerFactory commandHandlerFactory,
+ [Frozen] IStateProjector stateProjector,
+ [Frozen] IStateWriter stateWriter,
+ CommandProcessor sut,
+ MockCommand command,
+ CommandResult commandResult,
+ MockCommandHandler handler,
+ MockEvent[] events,
+ Atc.Cosmos.EventStore.Cqrs.Commands.StreamState streamState,
+ CancellationToken cancellationToken)
+ {
+ commandHandlerFactory.Create().Returns(handler);
+ stateProjector.ProjectAsync(command, handler, cancellationToken).Returns(streamState);
+ stateWriter.WriteEventAsync(command, events, cancellationToken).ReturnsForAnyArgs(commandResult);
+ handler.AddEventsToEmit(events);
+
+ await sut.ExecuteAsync(command, cancellationToken);
+
+ await stateWriter.Received(1).WriteEventAsync(command, Arg.Any>(), cancellationToken);
+ var writtenEvents = stateWriter.ReceivedCallWithArgument>();
+ writtenEvents.Should().HaveSameCount(events);
+ writtenEvents.AsEnumerable().Should().BeEquivalentTo(events);
+ }
+
+ [Theory, AutoNSubstituteData]
+ internal async Task Should_Return_Changed_When_Command_Emits_Events(
+ [Frozen] ICommandHandlerFactory commandHandlerFactory,
+ [Frozen] IStateProjector stateProjector,
+ [Frozen] IStateWriter stateWriter,
+ CommandProcessor sut,
+ MockCommand command,
+ MockCommandHandler handler,
+ CommandResult commandResult,
+ MockEvent[] events,
+ Atc.Cosmos.EventStore.Cqrs.Commands.StreamState streamState,
+ CancellationToken cancellationToken)
+ {
+ commandHandlerFactory.Create().Returns(handler);
+ stateProjector.ProjectAsync(command, handler, cancellationToken).Returns(streamState);
+ stateWriter.WriteEventAsync(command, events, cancellationToken).ReturnsForAnyArgs(commandResult);
+ handler.AddEventsToEmit(events);
+
+ var result = await sut.ExecuteAsync(command, cancellationToken);
+
+ result.Result.Should().Be(ResultType.Changed);
+ }
+
+ [Theory, AutoNSubstituteData]
+ internal async Task Should_Write_ResposeObject_To_CommandResult_When_Command_Emits_Events(
+ [Frozen] ICommandHandlerFactory commandHandlerFactory,
+ [Frozen] IStateProjector stateProjector,
+ [Frozen] IStateWriter stateWriter,
+ CommandProcessor sut,
+ MockCommand command,
+ MockCommandHandler handler,
+ CommandResult commandResult,
+ MockEvent[] events,
+ object responseObject,
+ Atc.Cosmos.EventStore.Cqrs.Commands.StreamState streamState,
+ CancellationToken cancellationToken)
+ {
+ commandHandlerFactory.Create().Returns(handler);
+ stateProjector.ProjectAsync(command, handler, cancellationToken).Returns(streamState);
+ stateWriter.WriteEventAsync(command, events, cancellationToken).ReturnsForAnyArgs(commandResult);
+ handler.AddEventsToEmit(events);
+ handler.ResponseObject = responseObject;
+
+ var result = await sut.ExecuteAsync(command, cancellationToken);
+
+ result.Response.Should().Be(responseObject);
+ }
+}
\ No newline at end of file
diff --git a/test/Atc.Cosmos.EventStore.Cqrs.Tests/Mocks/MockCommandHandler.cs b/test/Atc.Cosmos.EventStore.Cqrs.Tests/Mocks/MockCommandHandler.cs
new file mode 100644
index 0000000..e9405c6
--- /dev/null
+++ b/test/Atc.Cosmos.EventStore.Cqrs.Tests/Mocks/MockCommandHandler.cs
@@ -0,0 +1,28 @@
+namespace Atc.Cosmos.EventStore.Cqrs.Tests.Mocks;
+
+public class MockCommandHandler : ICommandHandler
+{
+ private List events = new();
+
+ public object ResponseObject { get; set; } = null;
+
+ public void AddEventsToEmit(params IEvent[] eventsToEmit)
+ {
+ events = events.Concat(eventsToEmit).ToList();
+ }
+
+ public ValueTask ExecuteAsync(
+ MockCommand command,
+ ICommandContext context,
+ CancellationToken cancellationToken)
+ {
+ foreach (var evt in events)
+ {
+ context.AddEvent(evt);
+ }
+
+ context.ResponseObject = ResponseObject;
+
+ return default;
+ }
+}
\ No newline at end of file
diff --git a/test/Atc.Cosmos.EventStore.IntegrationTests/Atc.Cosmos.EventStore.IntegrationTests.csproj b/test/Atc.Cosmos.EventStore.IntegrationTests/Atc.Cosmos.EventStore.IntegrationTests.csproj
index 4dbcbbb..58afc86 100644
--- a/test/Atc.Cosmos.EventStore.IntegrationTests/Atc.Cosmos.EventStore.IntegrationTests.csproj
+++ b/test/Atc.Cosmos.EventStore.IntegrationTests/Atc.Cosmos.EventStore.IntegrationTests.csproj
@@ -1,20 +1,20 @@
- net7.0
+ net9.0
false
-
-
-
-
-
+
+
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/test/Atc.Cosmos.EventStore.Tests/Atc.Cosmos.EventStore.Tests.csproj b/test/Atc.Cosmos.EventStore.Tests/Atc.Cosmos.EventStore.Tests.csproj
index 0ffa593..5f3743f 100644
--- a/test/Atc.Cosmos.EventStore.Tests/Atc.Cosmos.EventStore.Tests.csproj
+++ b/test/Atc.Cosmos.EventStore.Tests/Atc.Cosmos.EventStore.Tests.csproj
@@ -1,20 +1,20 @@
- net7.0
+ net9.0
false
-
-
-
-
-
+
+
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/test/Atc.Cosmos.EventStore.Tests/Converters/EventDataConverterPipelineBuilderTests.cs b/test/Atc.Cosmos.EventStore.Tests/Converters/EventDataConverterPipelineBuilderTests.cs
index a66c37e..2e24e07 100644
--- a/test/Atc.Cosmos.EventStore.Tests/Converters/EventDataConverterPipelineBuilderTests.cs
+++ b/test/Atc.Cosmos.EventStore.Tests/Converters/EventDataConverterPipelineBuilderTests.cs
@@ -14,7 +14,6 @@ public class EventDataConverterPipelineBuilderTests
[Theory, AutoNSubstituteData]
internal void Should_Call_All_Converters_InReverseOrder(
IEventMetadata metadata,
- JsonSerializerOptions options,
FakeEventDataConverter[] converters,
FakeEventDataConverter converter,
EventDataConverterPipelineBuilder sut)
@@ -22,7 +21,7 @@ internal void Should_Call_All_Converters_InReverseOrder(
.AddConverter(converter)
.AddConverters(converters)
.Build()
- .Convert(metadata, doc.RootElement, options)
+ .Convert(metadata, doc.RootElement, new JsonSerializerOptions())
.Should()
.Be(string.Join(string.Empty, new[] { converter }.Concat(converters).Select(c => c.Val)));
}
diff --git a/test/Atc.Cosmos.EventStore.Tests/Converters/FaultedEventDataConverterTests.cs b/test/Atc.Cosmos.EventStore.Tests/Converters/FaultedEventDataConverterTests.cs
index 274b85f..937c431 100644
--- a/test/Atc.Cosmos.EventStore.Tests/Converters/FaultedEventDataConverterTests.cs
+++ b/test/Atc.Cosmos.EventStore.Tests/Converters/FaultedEventDataConverterTests.cs
@@ -14,14 +14,13 @@ public class FaultedEventDataConverterTests
[Theory, AutoNSubstituteData]
internal void Should_Return_Converted_Value(
IEventMetadata metadata,
- JsonSerializerOptions options,
string expected,
FaultedEventDataConverter sut)
=> sut
.Convert(
metadata,
doc.RootElement,
- options,
+ new JsonSerializerOptions(),
() => expected)
.Should()
.Be(expected);
@@ -29,14 +28,13 @@ internal void Should_Return_Converted_Value(
[Theory, AutoNSubstituteData]
internal void Should_Return_FaultedEvent_When_Exception_IsThrown(
IEventMetadata metadata,
- JsonSerializerOptions options,
KeyNotFoundException exception,
FaultedEventDataConverter sut)
=> sut
.Convert(
metadata,
doc.RootElement,
- options,
+ new JsonSerializerOptions(),
() => throw exception)
.Should()
.BeEquivalentTo(
diff --git a/test/Atc.Cosmos.EventStore.Tests/Converters/NamedEventConverterTests.cs b/test/Atc.Cosmos.EventStore.Tests/Converters/NamedEventConverterTests.cs
index 913e4ff..a731f7e 100644
--- a/test/Atc.Cosmos.EventStore.Tests/Converters/NamedEventConverterTests.cs
+++ b/test/Atc.Cosmos.EventStore.Tests/Converters/NamedEventConverterTests.cs
@@ -18,7 +18,6 @@ public class NamedEventConverterTests
internal void Should_Return_Value_FromNext_When_TypeName_IsNotFound(
[Frozen] IEventTypeProvider typeProvider,
IEventMetadata metadata,
- JsonSerializerOptions options,
string expected,
NamedEventConverter sut)
{
@@ -30,7 +29,7 @@ internal void Should_Return_Value_FromNext_When_TypeName_IsNotFound(
.Convert(
metadata,
doc.RootElement,
- options,
+ new JsonSerializerOptions(),
() => expected)
.Should()
.Be(expected);
diff --git a/test/Atc.Cosmos.EventStore.Tests/Converters/UnknownEventDataConverterTests.cs b/test/Atc.Cosmos.EventStore.Tests/Converters/UnknownEventDataConverterTests.cs
index 74529be..4651141 100644
--- a/test/Atc.Cosmos.EventStore.Tests/Converters/UnknownEventDataConverterTests.cs
+++ b/test/Atc.Cosmos.EventStore.Tests/Converters/UnknownEventDataConverterTests.cs
@@ -14,14 +14,13 @@ public class UnknownEventDataConverterTests
[Theory, AutoNSubstituteData]
internal void Should_Return_Converted_Value_Id_NotNull(
IEventMetadata metadata,
- JsonSerializerOptions options,
string expected,
UnknownEventDataConverter sut)
=> sut
.Convert(
metadata,
doc.RootElement,
- options,
+ new JsonSerializerOptions(),
() => expected)
.Should()
.Be(expected);
@@ -29,13 +28,12 @@ internal void Should_Return_Converted_Value_Id_NotNull(
[Theory, AutoNSubstituteData]
internal void Should_Return_UnknownEvent_When_Value_IsNot_Converted(
IEventMetadata metadata,
- JsonSerializerOptions options,
UnknownEventDataConverter sut)
=> sut
.Convert(
metadata,
doc.RootElement,
- options,
+ new JsonSerializerOptions(),
() => null)
.Should()
.BeEquivalentTo(
diff --git a/test/Atc.Cosmos.EventStore.Tests/Cosmos/CosmosDeleterTests.cs b/test/Atc.Cosmos.EventStore.Tests/Cosmos/CosmosDeleterTests.cs
new file mode 100644
index 0000000..bf2d3b3
--- /dev/null
+++ b/test/Atc.Cosmos.EventStore.Tests/Cosmos/CosmosDeleterTests.cs
@@ -0,0 +1,50 @@
+using Atc.Cosmos.EventStore.Cosmos;
+using Atc.Test;
+using Microsoft.Azure.Cosmos;
+using NSubstitute;
+using Xunit;
+
+namespace Atc.Cosmos.EventStore.Tests.Cosmos;
+
+public class CosmosDeleterTests
+{
+ private readonly ResponseMessage responseMessage;
+ private readonly Container container;
+ private readonly IEventStoreContainerProvider containerProvider;
+ private readonly CosmosDeleter sut;
+
+ public CosmosDeleterTests()
+ {
+ responseMessage = Substitute.For();
+ responseMessage.IsSuccessStatusCode.Returns(true);
+
+ container = Substitute.For();
+ container
+ .DeleteAllItemsByPartitionKeyStreamAsync(default, default, default)
+ .ReturnsForAnyArgs(responseMessage);
+
+ containerProvider = Substitute.For();
+ containerProvider
+ .GetStreamContainer()
+ .Returns(container, returnThese: null);
+
+ sut = new CosmosDeleter(containerProvider);
+ }
+
+ [Theory, AutoNSubstituteData]
+ public async Task Should_Use_StreamId_As_PartitionKey(
+ StreamId streamId,
+ CancellationToken cancellationToken)
+ {
+ await sut.DeleteAsync(
+ streamId,
+ cancellationToken);
+
+ _ = container
+ .Received()
+ .DeleteAllItemsByPartitionKeyStreamAsync(
+ new PartitionKey(streamId.Value),
+ null,
+ cancellationToken);
+ }
+}
\ No newline at end of file
diff --git a/test/Atc.Cosmos.EventStore.Tests/EventStoreClientTests.cs b/test/Atc.Cosmos.EventStore.Tests/EventStoreClientTests.cs
index 3d5903a..87df0e0 100644
--- a/test/Atc.Cosmos.EventStore.Tests/EventStoreClientTests.cs
+++ b/test/Atc.Cosmos.EventStore.Tests/EventStoreClientTests.cs
@@ -1,6 +1,5 @@
using System.Collections.ObjectModel;
using Atc.Cosmos.EventStore.Cosmos;
-using Atc.Cosmos.EventStore.Events;
using Atc.Cosmos.EventStore.Streams;
using Atc.Test;
using AutoFixture.AutoNSubstitute;
@@ -104,7 +103,7 @@ await sut
}
[Theory, AutoNSubstituteData]
- internal async Task Should_Throw_When_EventsList_Containes_NullObject(
+ internal async Task Should_Throw_When_EventsList_Contains_NullObject(
EventStoreClient sut,
StreamId streamId,
Collection events,
diff --git a/test/Atc.Cosmos.EventStore.Tests/EventStoreManagementClientTests.cs b/test/Atc.Cosmos.EventStore.Tests/EventStoreManagementClientTests.cs
new file mode 100644
index 0000000..6c1c670
--- /dev/null
+++ b/test/Atc.Cosmos.EventStore.Tests/EventStoreManagementClientTests.cs
@@ -0,0 +1,29 @@
+using Atc.Cosmos.EventStore.Streams;
+using Atc.Test;
+using AutoFixture.Xunit2;
+using FluentAssertions;
+using NSubstitute;
+using Xunit;
+
+namespace Atc.Cosmos.EventStore.Tests;
+
+public class EventStoreManagementClientTests
+{
+ [Theory, AutoNSubstituteData]
+ internal async Task Should_DeleteStream(
+ [Frozen] IStreamDeleter deleter,
+ EventStoreManagementClient sut,
+ StreamId streamId,
+ CancellationToken cancellationToken)
+ {
+ await sut.DeleteStreamAsync(
+ streamId,
+ cancellationToken: cancellationToken);
+
+ _ = deleter
+ .Received(1)
+ .DeleteAsync(
+ streamId,
+ cancellationToken);
+ }
+}
\ No newline at end of file
diff --git a/test/Atc.Cosmos.EventStore.Tests/Streams/StreamInfoReaderTests.cs b/test/Atc.Cosmos.EventStore.Tests/Streams/StreamInfoReaderTests.cs
index dd5b655..5c3339b 100644
--- a/test/Atc.Cosmos.EventStore.Tests/Streams/StreamInfoReaderTests.cs
+++ b/test/Atc.Cosmos.EventStore.Tests/Streams/StreamInfoReaderTests.cs
@@ -23,8 +23,7 @@ internal async Task Should_Convert_Into_StreamResponse(
.ReturnsForAnyArgs(expectedMetadata);
var info = await sut
- .ReadAsync(streamId, cancellationToken)
- .ConfigureAwait(false);
+ .ReadAsync(streamId, cancellationToken);
info
.State
@@ -57,8 +56,7 @@ internal async Task Should_Read_Metadata_From_Stream(
.ReturnsForAnyArgs(expectedMetadata);
await sut
- .ReadAsync(streamId, cancellationToken)
- .ConfigureAwait(false);
+ .ReadAsync(streamId, cancellationToken);
_ = metadataReader
.Received(1)
diff --git a/version.json b/version.json
index db87276..f03d338 100644
--- a/version.json
+++ b/version.json
@@ -1,6 +1,6 @@
{
"$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json",
- "version": "1.13",
+ "version": "1.14",
"assemblyVersion": {
"precision": "revision"
},