Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 42 additions & 41 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,29 @@
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<PropertyGroup Label="Package versions for .NET 10" Condition="'$(TargetFramework)' == 'net10.0'">
<MicrosoftTestHostVer>10.0.0</MicrosoftTestHostVer>
<MicrosoftExtensionsVer>10.0.0</MicrosoftExtensionsVer>
<MicrosoftTestHostVer>10.0.10</MicrosoftTestHostVer>
<MicrosoftExtensionsVer>10.0.10</MicrosoftExtensionsVer>
</PropertyGroup>
<PropertyGroup Label="Package versions for .NET 9" Condition="'$(TargetFramework)' == 'net9.0'">
<MicrosoftTestHostVer>9.0.10</MicrosoftTestHostVer>
<MicrosoftExtensionsVer>9.0.10</MicrosoftExtensionsVer>
<MicrosoftTestHostVer>9.0.18</MicrosoftTestHostVer>
<MicrosoftExtensionsVer>10.0.10</MicrosoftExtensionsVer>
</PropertyGroup>
<PropertyGroup Label="Package versions for .NET 8" Condition="'$(TargetFramework)' == 'net8.0'">
<MicrosoftTestHostVer>8.0.21</MicrosoftTestHostVer>
<MicrosoftExtensionsVer>9.0.10</MicrosoftExtensionsVer>
<MicrosoftTestHostVer>8.0.29</MicrosoftTestHostVer>
<MicrosoftExtensionsVer>10.0.10</MicrosoftExtensionsVer>
</PropertyGroup>
<PropertyGroup Label="Testcontainers version">
<TestcontainersVersion>4.10.0</TestcontainersVersion>
<TestcontainersVersion>4.13.0</TestcontainersVersion>
</PropertyGroup>
<PropertyGroup>
<NpgsqlVersion>10.0.1</NpgsqlVersion>
<TUnitVersion>0.77.3</TUnitVersion>
<NpgsqlVersion>10.0.3</NpgsqlVersion>
<TUnitVersion>1.63.0</TUnitVersion>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="BenchmarkDotNet" Version="0.14.0" />
<PackageVersion Include="BenchmarkDotNet" Version="0.15.8" />
<PackageVersion Include="FluentValidation" Version="12.0.0" />
<PackageVersion Include="IsExternalInit" Version="1.0.3" />
<PackageVersion Include="KurrentDB.Client" Version="1.3.0" />
<PackageVersion Include="KurrentDB.Client" Version="1.4.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="$(MicrosoftExtensionsVer)" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="$(MicrosoftExtensionsVer)" />
<PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="$(MicrosoftExtensionsVer)" />
Expand All @@ -39,23 +39,24 @@
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageVersion Include="Shouldly" Version="4.2.1" />
<PackageVersion Include="System.Diagnostics.DiagnosticSource" Version="$(MicrosoftExtensionsVer)" />
<PackageVersion Include="System.Linq.AsyncEnumerable" Version="10.0.0" />
<PackageVersion Include="System.Reactive" Version="6.0.1" />
<PackageVersion Include="OpenTelemetry.Api" Version="1.15.3" />
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.15.3" />
<PackageVersion Include="MongoDB.Driver" Version="3.4.0" />
<PackageVersion Include="System.Linq.AsyncEnumerable" Version="10.0.10" />
<PackageVersion Include="System.Reactive" Version="7.0.0" />
<PackageVersion Include="OpenTelemetry.Api" Version="1.17.0" />
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.17.0" />
<PackageVersion Include="MongoDB.Driver" Version="3.10.0" />
<PackageVersion Include="Google.Cloud.PubSub.V1" Version="3.19.0" />
<PackageVersion Include="Confluent.Kafka" Version="2.6.1" />
<PackageVersion Include="Confluent.Kafka" Version="2.15.0" />
<PackageVersion Include="Npgsql" Version="$(NpgsqlVersion)" />
<PackageVersion Include="Npgsql.DependencyInjection" Version="$(NpgsqlVersion)" />
<PackageVersion Include="RabbitMQ.Client" Version="6.8.1" />
<PackageVersion Include="Microsoft.Data.SqlClient" Version="6.0.2" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="9.0.6" />
<PackageVersion Include="RabbitMQ.Client" Version="7.2.1" />
<PackageVersion Include="Microsoft.Data.SqlClient" Version="7.0.2" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="10.0.10" />
<PackageVersion Include="SQLitePCLRaw.lib.e_sqlite3" Version="2.1.12" />
<PackageVersion Include="NEST" Version="7.17.5" />
<PackageVersion Include="Polly" Version="8.5.0" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="StackExchange.Redis" Version="2.10.1" />
<PackageVersion Include="Azure.Messaging.ServiceBus" Version="7.20.1" />
<PackageVersion Include="StackExchange.Redis" Version="3.1.0" />
<PackageVersion Include="Azure.Messaging.ServiceBus" Version="7.20.2" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" PrivateAssets="all" />
<PackageVersion Include="Microsoft.CodeAnalysis" Version="4.10.0" PrivateAssets="all" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.10.0" PrivateAssets="all" />
Expand All @@ -72,50 +73,50 @@
<PackageVersion Include="Testcontainers.ServiceBus" Version="$(TestcontainersVersion)" />
</ItemGroup>
<ItemGroup Label="References for packable projects">
<PackageVersion Include="MinVer" Version="6.0.0" PrivateAssets="All" />
<PackageVersion Include="JetBrains.Annotations" Version="2024.3.0" PrivateAssets="All" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
<PackageVersion Include="MinVer" Version="7.0.0" PrivateAssets="All" />
<PackageVersion Include="JetBrains.Annotations" Version="2026.2.0" PrivateAssets="All" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="10.0.301" PrivateAssets="All" />
</ItemGroup>
<ItemGroup Label="References for test projects">
<PackageVersion Include="AutoFixture" Version="4.18.1" />
<PackageVersion Include="MicroElements.AutoFixture.NodaTime" Version="1.0.0" />
<PackageVersion Include="Bogus" Version="35.6.1" />
<PackageVersion Include="coverlet.collector" Version="6.0.4" PrivateAssets="All" />
<PackageVersion Include="Bogus" Version="35.6.5" />
<PackageVersion Include="coverlet.collector" Version="10.0.1" PrivateAssets="All" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="$(MicrosoftTestHostVer)" />
<PackageVersion Include="Microsoft.AspNetCore.TestHost" Version="$(MicrosoftTestHostVer)" />
<PackageVersion Include="RestSharp" Version="112.1.0" />
<PackageVersion Include="RestSharp" Version="114.0.0" />
<PackageVersion Include="Hypothesist" Version="3.0.97" />
<PackageVersion Include="NodaTime" Version="3.3.0" />
<PackageVersion Include="NodaTime.Serialization.SystemTextJson" Version="1.2.0" />
<PackageVersion Include="NodaTime" Version="3.3.3" />
<PackageVersion Include="NodaTime.Serialization.SystemTextJson" Version="1.4.0" />
<PackageVersion Include="MongoDb.Bson.NodaTime" Version="3.1.0" />
<PackageVersion Include="Verify.DiffPlex" Version="3.1.2" />
<PackageVersion Include="TUnit" Version="$(TUnitVersion)" />
<PackageVersion Include="TUnit.Core" Version="$(TUnitVersion)" />
<PackageVersion Include="TUnit.Assertions" Version="$(TUnitVersion)" />
<PackageVersion Include="Microsoft.Testing.Extensions.TrxReport" Version="2.0.1" />
<PackageVersion Include="Microsoft.Testing.Extensions.TrxReport" Version="2.3.3" />
<PackageVersion Include="Verify.TUnit" Version="31.0.5" />
<PackageVersion Include="NodaTime.Bogus" Version="3.0.2" />
<PackageVersion Include="System.Text.Json" Version="9.0.6" />
<PackageVersion Include="NSubstitute" Version="5.3.0" />
<PackageVersion Include="System.Text.Json" Version="10.0.10" />
<PackageVersion Include="NSubstitute" Version="6.0.0" />
</ItemGroup>
<ItemGroup Label="SignalR packages">
<PackageVersion Include="Microsoft.AspNetCore.SignalR.Common" Version="10.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.SignalR.Client" Version="10.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.SignalR.Client" Version="10.0.10" />
</ItemGroup>
<ItemGroup Label="Packages for samples">
<PackageVersion Include="MongoDB.Driver.Core.Extensions.DiagnosticSources" Version="2.1.0" />
<PackageVersion Include="MongoDB.Driver.Core.Extensions.DiagnosticSources" Version="3.0.0" />
<PackageVersion Include="MongoDB.Driver.Core" Version="2.30.0" />
<PackageVersion Include="Npgsql.OpenTelemetry" Version="$(NpgsqlVersion)" />
<PackageVersion Include="OpenTelemetry" Version="1.15.3" />
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.15.3" />
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.17.0" />
<PackageVersion Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" Version="1.15.3-beta.1" />
<PackageVersion Include="OpenTelemetry.Exporter.Zipkin" Version="1.15.3" />
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.15.2" />
<PackageVersion Include="OpenTelemetry.Exporter.Zipkin" Version="1.17.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.17.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.GrpcNetClient" Version="1.15.1-beta.1" />
<PackageVersion Include="Serilog.AspNetCore" Version="9.0.0" />
<PackageVersion Include="Serilog.Extensions.Hosting" Version="9.0.0" />
<PackageVersion Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageVersion Include="Serilog.Sinks.Seq" Version="9.0.0" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="9.0.1" />
<PackageVersion Include="Serilog.Sinks.Console" Version="6.1.1" />
<PackageVersion Include="Serilog.Sinks.Seq" Version="9.1.0" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="10.2.3" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ static BadRequestObjectResult MapValidationExceptionAsValidationProblemDetails(R
var groupFailures = exception.Errors.GroupBy(v => v.PropertyName);

foreach (var groupFailure in groupFailures) {
problemDetails.Errors.Add(groupFailure.Key, groupFailure.Select(s => s.ErrorMessage).ToArray());
problemDetails.Errors.Add(groupFailure.Key, [.. groupFailure.Select(s => s.ErrorMessage)]);
}

return new(problemDetails);
Expand Down
5 changes: 1 addition & 4 deletions samples/postgres/Bookings.Payments/Registrations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@ namespace Bookings.Payments;

public static class Registrations {
public static void AddEventuous(this IServiceCollection services, IConfiguration configuration) {
var connectionFactory = new ConnectionFactory {
Uri = new(configuration["RabbitMq:ConnectionString"]!),
DispatchConsumersAsync = true
};
var connectionFactory = new ConnectionFactory { Uri = new(configuration["RabbitMq:ConnectionString"]!) };
services.AddSingleton(connectionFactory);
services.AddEventuousPostgres(configuration.GetSection("Postgres"));
services.AddEventStore<PostgresStore>();
Expand Down
5 changes: 1 addition & 4 deletions samples/postgres/Bookings/Registrations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@ public static void AddEventuous(this IServiceCollection services, IConfiguration
new DefaultEventSerializer(new JsonSerializerOptions(JsonSerializerDefaults.Web).ConfigureForNodaTime(DateTimeZoneProviders.Tzdb))
);

var connectionFactory = new ConnectionFactory {
Uri = new(configuration["RabbitMq:ConnectionString"]!),
DispatchConsumersAsync = true
};
var connectionFactory = new ConnectionFactory { Uri = new(configuration["RabbitMq:ConnectionString"]!) };

services.AddSingleton(connectionFactory);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public async Task CorrelationId() {

[Test]
public async Task ScheduledEnqueueTime() =>
await Assert.That(_message.ScheduledEnqueueTime).IsEqualTo(new DateTimeOffset(2026, 3, 23, 16, 31, 0, TimeSpan.Zero));
await Assert.That(_message.ScheduledEnqueueTime).IsEqualTo(new(2026, 3, 23, 16, 31, 0, TimeSpan.Zero));

[Test]
[Arguments("MessageId")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
namespace Eventuous.Tests.Azure.ServiceBus;

public class IsSerialisableByServiceBus {
// TUnit0046 is a false positive: the data sources already return Func<object?> for test isolation,
// and the runtime invokes the Func, but the analyzer can't detect the wrapper when the test parameter is object
#pragma warning disable TUnit0046
public static IEnumerable<Func<object?>> PassingTestData() {
yield return () => "string";
yield return () => 123;
Expand Down Expand Up @@ -34,12 +37,13 @@ public class IsSerialisableByServiceBus {
yield return () => new Action(() => { }); // delegate
yield return () => new WeakReference(new()); // complex type
}
#pragma warning restore TUnit0046

[Test]
[MethodDataSource(nameof(PassingTestData))]
public async Task Passes(object value) => await Assert.That(IsSerialisableByServiceBus(value)).IsTrue();
public async Task Passes(object? value) => await Assert.That(IsSerialisableByServiceBus(value)).IsTrue();

[Test]
[MethodDataSource(nameof(FailingTestData))]
public async Task Fails(object value) => await Assert.That(IsSerialisableByServiceBus(value)).IsFalse();
public async Task Fails(object? value) => await Assert.That(IsSerialisableByServiceBus(value)).IsFalse();
}
26 changes: 12 additions & 14 deletions src/Azure/test/Eventuous.Tests.Azure.ServiceBus/SendAndReceive.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ namespace Eventuous.Tests.Azure.ServiceBus;
[NotInParallel]
[TopicAndQueueSource]
public class SendAndReceive {
static CancellationToken TestCancellationToken => TestContext.Current!.CancellationToken;

ServiceBusProducer _producer = null!;
ServiceBusSubscription _subscription = null!;

Expand All @@ -31,31 +29,31 @@ public SendAndReceive(AzureServiceBusFixture fixture, ServiceBusProducerOptions

[Test]
[Retry(3)]
public async Task SingleMessage() {
await _producer.Produce(_streamName, SomeEvent.Create(), _metadata, cancellationToken: TestCancellationToken);
public async Task SingleMessage(CancellationToken cancellationToken) {
await _producer.Produce(_streamName, SomeEvent.Create(), _metadata, cancellationToken: cancellationToken);

// Assert
await _handler.AssertThat()
.Timebox(TimeSpan.FromSeconds(5))
.Single()
.Match(evt => evt is SomeEvent)
.Validate(TestCancellationToken);
.Validate(cancellationToken);
}

[Test]
[Retry(3)]
public async Task LoadsOfMessages() {
public async Task LoadsOfMessages(CancellationToken cancellationToken) {
const int count = 200;

var events = Enumerable.Range(0, count).Select(SomeEvent.Create).ToList();
await _producer.Produce(_streamName, events, _metadata, cancellationToken: TestCancellationToken);
await _producer.Produce(_streamName, events, _metadata, cancellationToken: cancellationToken);

// Assert
await _handler.AssertThat()
.Timebox(TimeSpan.FromSeconds(20))
.Exactly(count)
.Match(evt => evt is SomeEvent)
.Validate(TestCancellationToken);
.Validate(cancellationToken);

var handledMessageIds = _handler.Messages
.OfType<SomeEvent>()
Expand All @@ -66,19 +64,19 @@ await _handler.AssertThat()
}

[After(Test)]
public async ValueTask CleanUpProducerAndSubscription() {
await _producer.StopAsync(TestCancellationToken);
await _subscription.Unsubscribe(_ => { }, TestCancellationToken);
public async ValueTask CleanUpProducerAndSubscription(CancellationToken cancellationToken) {
await _producer.StopAsync(cancellationToken);
await _subscription.Unsubscribe(_ => { }, cancellationToken);
await _subscription.DisposeAsync();
await _producer.DisposeAsync();
}

[Before(Test)]
public async Task StartProducerAndSubscription() {
public async Task StartProducerAndSubscription(CancellationToken cancellationToken) {
_producer = _fixture.CreateProducer(_serviceBusProducerOptions);
_subscription = _fixture.CreateSubscription(_serviceBusSubscriptionOptions, _handler, _correlationId);

await _producer.StartAsync(TestCancellationToken);
await _subscription.Subscribe(_ => { }, (_, _, _) => { }, TestCancellationToken);
await _producer.StartAsync(cancellationToken);
await _subscription.Subscribe(_ => { }, (_, _, _) => { }, cancellationToken);
}
}
5 changes: 3 additions & 2 deletions src/Benchmarks/Benchmarks/ChannelBatchingBenchmarks.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using BenchmarkDotNet.Attributes;
using System.Buffers;
using System.Runtime.InteropServices;

namespace Benchmarks;

Expand All @@ -26,12 +27,12 @@ public void Setup() {

[Benchmark(Baseline = true, Description = "Current: List.ToArray()")]
public int[] CurrentApproach_ToArray() {
return _buffer.ToArray();
return [.. _buffer];
}

[Benchmark(Description = "Alternative 1: CollectionsMarshal.AsSpan()")]
public ReadOnlySpan<int> Alternative1_CollectionsMarshalAsSpan() {
return System.Runtime.InteropServices.CollectionsMarshal.AsSpan(_buffer);
return CollectionsMarshal.AsSpan(_buffer);
}

[Benchmark(Description = "Alternative 2: ArrayPool rent/copy")]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using BenchmarkDotNet.Attributes;
using Eventuous;
using Eventuous.Subscriptions;
using Eventuous.Subscriptions.Context;

Expand Down Expand Up @@ -93,7 +94,8 @@ public async Task CreateContextAndProcess() {
await _handler.HandleEvent(ctx);
}

class TestEvent {
[EventType("benchmark-test-event")]
internal class TestEvent {
public string Value { get; set; } = string.Empty;
}

Expand Down
10 changes: 1 addition & 9 deletions src/Core/gen/Eventuous.Shared.Generators/EventUsageAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,15 +141,7 @@ static void AnalyzeInvocation(OperationAnalysisContext ctx, KnownTypeSymbols kno
return;
}
// Case 1c: State<T>.On<TEvent>(...) handler registrations
case { Name: "On", TypeArguments.Length: 1 } when IsState(method.ContainingType, knownTypes): {
var eventType = method.TypeArguments[0];

if (IsConcreteEvent(eventType) && !HasEventTypeAttribute(eventType, knownTypes) && !IsExplicitlyRegistered(eventType, ctx, knownTypes)) {
ctx.ReportDiagnostic(Diagnostic.Create(MissingEventTypeAttribute, inv.Syntax.GetLocation(), eventType.ToDisplayString()));
}

return;
}
case { Name: "On", TypeArguments.Length: 1 } when IsState(method.ContainingType, knownTypes):
// Case 1d: EventHandler.On<T>(...) handler registrations
case { Name: "On", TypeArguments.Length: 1 } when IsEventHandler(method.ContainingType, knownTypes): {
var eventType = method.TypeArguments[0];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ void ProcessNamespace(INamespaceSymbol ns, bool isReferenced) {
}

static bool IsPublicType(INamedTypeSymbol type) {
for (var t = (ITypeSymbol)type; t != null; t = t.ContainingType) {
for (ITypeSymbol? t = type; t != null; t = t.ContainingType) {
if (t.DeclaredAccessibility != Accessibility.Public) return false;
}
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public async Task<Result<TState>> Handle<TCommand>(TCommand command, Cancellatio
// Zero in the global position would mean nothing, so the receiver needs to check the Changes.Length
if (result.Changes.Count == 0) return Result<TState>.FromSuccess(result.State, [], 0);

var proposed = new ProposedAppend(stream, new(result.OriginalVersion), result.Changes.Select(x => new ProposedEvent(x, new())).ToArray());
var proposed = new ProposedAppend(stream, new(result.OriginalVersion), [.. result.Changes.Select(x => new ProposedEvent(x, new()))]);
var final = registeredHandler.AmendAppend?.Invoke(proposed, command) ?? proposed;
var writer = registeredHandler.ResolveWriter(command);
var storeResult = await writer.Store(final, Amend, cancellationToken).NoContext();
Expand Down
Loading
Loading