V4.4.0/support for healthcheck#39
Conversation
…ements either IHealthCheckProvider or IAsyncHealthCheckProvider
…ed implementations
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughIntroduces new health-check provider interfaces and integrates health-target retrieval across NATS, RabbitMQ, Azure Queue Storage, and AWS SQS/SNS components. Refactors Azure Queue Storage to use QueueServiceClient centrally. Adds extensive unit tests and Moq dependencies. Updates README and Copilot testing guidelines. Adds 4.4.0 release notes across packages. Changes
Sequence Diagram(s)sequenceDiagram
participant C as Caller
participant N as NatsMessage (sync)
participant R as RabbitMqMessage (async)
participant A as AzureCommandQueue (sync)
participant E as AzureEventBus (sync)
participant S as AmazonCommandQueue (sync)
participant SNS as AmazonEventBus (sync)
rect rgb(245,248,250)
Note over C,N: Health target retrieval (sync)
C->>N: GetHealthCheckTarget()
N-->>C: INatsConnection
C->>A: GetHealthCheckTarget()
A-->>C: QueueServiceClient
C->>E: GetHealthCheckTarget()
E-->>C: Uri (/api/health)
C->>S: GetHealthCheckTarget()
S-->>C: IAmazonSQS
C->>SNS: GetHealthCheckTarget()
SNS-->>C: IAmazonSimpleNotificationService
end
rect rgb(240,250,245)
Note over C,R: Health target retrieval (async)
C->>R: GetHealthCheckTargetAsync()
alt connection initialized
R-->>C: IConnection (existing)
else not initialized
R->>R: Create connection via IConnectionFactory
R-->>C: IConnection (new)
end
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 💡 Knowledge Base configuration:
You can enable these sources in your CodeRabbit configuration. 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Pull Request Overview
This pull request prepares the Savvyio suite for version 4.4.0, introducing new health check interfaces and upgrading dependencies across many packages to ensure compatibility with .NET 8 and .NET 9.
- Introduces health check interfaces (
IHealthCheckProviderandIAsyncHealthCheckProvider) in theSavvyio.Diagnosticsnamespace - Implements health check functionality across AWS SQS/SNS, Azure Queue Storage, RabbitMQ, and NATS messaging extensions
- Updates release notes for version 4.4.0 across all packages with dependency upgrades and new health check features
Reviewed Changes
Copilot reviewed 56 out of 56 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Savvyio.Core/Diagnostics/IHealthCheckProvider.cs | Adds synchronous health check provider interface |
| src/Savvyio.Core/Diagnostics/IAsyncHealthCheckProvider.cs | Adds asynchronous health check provider interface |
| src/Savvyio.Extensions.SimpleQueueService/EventDriven/AmazonEventBus.cs | Implements health check provider for AWS SNS |
| src/Savvyio.Extensions.SimpleQueueService/Commands/AmazonCommandQueue.cs | Implements health check provider for AWS SQS |
| src/Savvyio.Extensions.RabbitMQ/RabbitMqMessage.cs | Implements async health check provider for RabbitMQ |
| src/Savvyio.Extensions.QueueStorage/EventDriven/AzureEventBus.cs | Implements health check provider for Azure Event Grid |
| src/Savvyio.Extensions.QueueStorage/Commands/AzureCommandQueue.cs | Implements health check provider for Azure Queue Storage |
| src/Savvyio.Extensions.QueueStorage/AzureQueue.cs | Refactors to support QueueServiceClient access |
| src/Savvyio.Extensions.NATS/NatsMessage.cs | Implements health check provider for NATS |
| test/**.Tests/*.cs | Adds comprehensive unit tests for new health check functionality |
| Directory.Packages.props | Adds Moq package for testing |
| .nuget/**/PackageReleaseNotes.txt | Updates release notes for version 4.4.0 |
| README.md | Updates documentation with supported external dependencies |
| .github/copilot-instructions.md | Adds test doubles guidelines |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
README.md (1)
87-87: Correct package name typo: “Savvio.Core” → “Savvyio.Core”.Public-facing name mismatch undermines credibility; fix the label.
-| <font size="2">[Savvio.Core](https://www.nuget.org/packages/Savvyio.Core/)</font> |  |  |  | +| <font size="2">[Savvyio.Core](https://www.nuget.org/packages/Savvyio.Core/)</font> |  |  |  |
🧹 Nitpick comments (62)
README.md (2)
17-26: Fix section grammar and list punctuation for clarity/consistency.Use "Support for ..." and drop trailing commas/periods in bullets. Also remove the stray space after "Grid,".
-Supports for these external dependencies: +Support for these external dependencies: -- Dapper, +- Dapper -- Microsoft Entity Framework Core, +- Microsoft Entity Framework Core -- Marshaller for System.Text.Json, +- Marshaller for System.Text.Json -- Marshaller for Newtonsoft.Json, +- Marshaller for Newtonsoft.Json -- AWS SNS/SQS, +- AWS SNS/SQS -- Azure Queue Storage/Event Grid, +- Azure Queue Storage/Event Grid -- RabbitMQ, +- RabbitMQ -- NATS. +- NATS
33-34: Avoid HTML line break inside admonition.GitHub blockquotes render fine without
<br/>; prefer plain Markdown.-> Version 2.2.0 of Savvy I/O will be the last version to support .NET 7.<br/> +> Version 2.2.0 of Savvy I/O will be the last version to support .NET 7..nuget/Savvyio.Queries/PackageReleaseNotes.txt (1)
3-3: Normalize blank line whitespace.These lines appear to contain a non‑breaking space (NBSP). Prefer true empty lines to avoid encoding oddities in some viewers.
Apply:
- + - +Also applies to: 6-6
.nuget/Savvyio.Extensions.EFCore.Domain/PackageReleaseNotes.txt (1)
3-3: Replace non-breaking space with a true blank line.Line 3 appears to contain a non-breaking space (U+00A0). This can cause noisy diffs and encoding issues in editors/CI.
Apply this diff to normalize the blank line:
- +.nuget/Savvyio.Extensions.DependencyInjection.SimpleQueueService/PackageReleaseNotes.txt (1)
3-3: Replace NBSP-only lines with true blank lines.Lines contain a non-breaking space (U+00A0), which can create noisy diffs and encoding artifacts. Switch to empty lines.
- + - +Also applies to: 6-6
test/Savvyio.Extensions.RabbitMQ.Tests/Savvyio.Extensions.RabbitMQ.Tests.csproj (1)
6-9: Mark Moq as PrivateAssets to avoid unintended transitive flowEven though this is a test project, adding PrivateAssets=all is a common safeguard.
Apply:
<ItemGroup> - <PackageReference Include="Moq" /> + <PackageReference Include="Moq" PrivateAssets="all" /> </ItemGroup>.nuget/Savvyio.App/PackageReleaseNotes.txt (1)
1-33: Release notes block added — remove non‑breaking spacesThere are NBSP (U+00A0) “blank” lines that create noisy diffs. Replace with true empty lines.
Apply (example around the new header):
Version: 4.4.0 Availability: .NET 9 and .NET 8 - + # References.nuget/Savvyio.Extensions.DapperExtensions/PackageReleaseNotes.txt (1)
1-6: 4.4.0 notes added — wording consistencyConsider standardizing ALM phrasing across packages (e.g., “Dependencies have been upgraded to the latest compatible versions for all supported TFMs.”).
.nuget/Savvyio.Commands.Messaging/PackageReleaseNotes.txt (1)
1-6: 4.4.0 ALM entry — remove NBSP lineLine 3 is a NBSP “blank” line; switch to a true empty line for clean diffs.
Apply:
Version: 4.4.0 Availability: .NET 9 and .NET 8 - + # ALMtest/Savvyio.Extensions.SimpleQueueService.Tests/Savvyio.Extensions.SimpleQueueService.Tests.csproj (1)
7-9: Moq reference via CPM looks good; consider isolating it as test-only.You're relying on central package management (no Version here), which is fine. Optionally add PrivateAssets="all" so Moq never flows transitively if this project is referenced.
- <PackageReference Include="Moq" /> + <PackageReference Include="Moq" PrivateAssets="all" />.nuget/Savvyio.Extensions.DependencyInjection.Text.Json/PackageReleaseNotes.txt (2)
3-3: Replace non-breaking space lines with true blank lines.There are NBSP characters used as spacer lines; prefer real empty lines to avoid invisible diff noise and formatting glitches.
- + - +Also applies to: 6-6
1-6: Replace non-breaking spaces in all .nuget//PackageReleaseNotes.txt files**
Non-breaking spaces were detected across many release-note files (e.g. lines 3, 6, 9, 12 in Savvyio.Extensions.DependencyInjection.Text.Json/PackageReleaseNotes.txt); replace them with regular spaces to avoid formatting issues..nuget/Savvyio.Extensions.Newtonsoft.Json/PackageReleaseNotes.txt (1)
3-3: Swap NBSP spacer lines for real blanks.- + - +Also applies to: 6-6
.nuget/Savvyio.Extensions.EFCore/PackageReleaseNotes.txt (1)
3-3: Normalize whitespace: remove NBSP-only lines.- + - +Also applies to: 6-6
.nuget/Savvyio.Messaging/PackageReleaseNotes.txt (1)
3-3: Replace NBSP spacer lines with empty lines.- + - +Also applies to: 6-6
.nuget/Savvyio.Commands/PackageReleaseNotes.txt (1)
3-3: Remove NBSP-only spacer lines.- + - +Also applies to: 6-6
.nuget/Savvyio.Extensions.DependencyInjection.EFCore.Domain/PackageReleaseNotes.txt (1)
1-6: Normalize blank lines in release notes
In .nuget/Savvyio.Extensions.DependencyInjection.EFCore.Domain/PackageReleaseNotes.txt (lines 3 & 6), blank lines contain non-breaking space characters (\u00A0). Replace them with plain empty lines—and apply the same across all PackageReleaseNotes.txt files—to avoid rendering issues..nuget/Savvyio.Extensions.Dispatchers/PackageReleaseNotes.txt (1)
1-6: 4.4.0 release notes entry reads wellMatches house style and placement above 4.3.0.
Minor: in .nuget/Savvyio.Extensions.Dispatchers/PackageReleaseNotes.txt blank lines at lines 3, 6, 9,… contain NBSP (U+00A0); replace with true empty lines for consistency.
.nuget/Savvyio.Extensions.Dapper/PackageReleaseNotes.txt (1)
1-6: Normalize blank lines in PackageReleaseNotes.txt
Detected non-breaking spaces on blank lines (e.g. lines 3, 6, 9, … up to 92); replace them with true empty lines..nuget/Savvyio.Extensions.EFCore.Domain.EventSourcing/PackageReleaseNotes.txt (1)
1-6: Replace non-breaking space–only lines with blank lines in PackageReleaseNotes.txt
There are NBSP characters on multiple spacer lines; switch them to standard empty lines for consistent formatting..nuget/Savvyio.Domain.EventSourcing/PackageReleaseNotes.txt (1)
3-6: Replace NBSP spacer lines and add terminal period for consistencyThe lines contain a non-breaking space character, which can render oddly. Also consider ending the ALM bullet with a period to match common style.
Apply:
- + # ALM -- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs). - +.nuget/Savvyio.Extensions.DependencyInjection.NATS/PackageReleaseNotes.txt (1)
3-6: Clean up NBSP spacer lines; optional punctuation tweakReplace NBSP-only lines with plain blank lines; consider a period at the end of the ALM bullet.
- + # ALM -- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs). - +.nuget/Savvyio.Extensions.DependencyInjection.Dapper/PackageReleaseNotes.txt (1)
3-6: Swap NBSP spacer lines for blanks; add periodMinor formatting/punctuation consistency.
- + # ALM -- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs). - +.nuget/Savvyio.Extensions.Text.Json/PackageReleaseNotes.txt (1)
3-6: Normalize blank lines and punctuationReplace NBSP-only spacer lines with regular blank lines; add a period after the ALM bullet.
- + # ALM -- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs). - +.nuget/Savvyio.Extensions.DependencyInjection.Domain/PackageReleaseNotes.txt (1)
3-6: Replace NBSP spacer lines; optional periodSmall formatting tidy-up and punctuation consistency.
- + # ALM -- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs). - +.nuget/Savvyio.Extensions.DependencyInjection.EFCore/PackageReleaseNotes.txt (1)
1-6: Normalize NBSP-only spacer lines to plain blanks.Lines 3 and 6 contain a non-breaking space character, which can render oddly and trigger grammar linters. Replace with empty lines.
Version: 4.4.0 Availability: .NET 9 and .NET 8 - + # ALM - CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) - +.nuget/Savvyio.Extensions.DependencyInjection.DapperExtensions/PackageReleaseNotes.txt (1)
1-6: Trim NBSP-only spacer lines.As above, swap Lines 3 and 6 from NBSP to real blank lines to avoid rendering/lint noise.
Version: 4.4.0 Availability: .NET 9 and .NET 8 - + # ALM - CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) - +src/Savvyio.Core/Diagnostics/IHealthCheckProvider.cs (1)
7-13: Optional: encode non-null contract for the target and clarify docs.If the target is required, constrain T and state non-null in the return docs. Keeps implementations explicit and avoids nullability ambiguity.
- public interface IHealthCheckProvider<out T> + public interface IHealthCheckProvider<out T> where T : notnull { /// <summary> /// Gets the underlying target used for probing health status. /// </summary> - /// <returns>The target instance of type <typeparamref name="T"/> used for health probing.</returns> + /// <returns>The target instance of type <typeparamref name="T"/> used for health probing. Never null.</returns> T GetHealthCheckTarget(); }.nuget/Savvyio.Extensions.DependencyInjection.Newtonsoft.Json/PackageReleaseNotes.txt (1)
1-6: Replace NBSP-only spacers with blank lines.Addresses the linter warnings and prevents odd rendering in some viewers.
Version: 4.4.0 Availability: .NET 9 and .NET 8 - + # ALM - CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) - +.nuget/Savvyio.Extensions.DependencyInjection/PackageReleaseNotes.txt (1)
1-6: Normalize NBSP-only spacer lines.Same whitespace nit: replace Lines 3 and 6 with true empty lines.
Version: 4.4.0 Availability: .NET 9 and .NET 8 - + # ALM - CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) - +.github/copilot-instructions.md (1)
111-117: Polish grammar/clarity in “Test Doubles” bullets.Minor wording fixes improve readability and align with the rest of the doc.
-## 8. Test Doubles - -- Preferred test doubles include dummies, fakes, stubs and spies if and when the design allows it. -- Under special circumstances, mock can be used (using Moq library). -- Before overriding methods, verify that the method is virtual or abstract; this rule also applies to mocks. -- Never mock IMarshaller; always use a new instance of JsonMarshaller. +## 8. Test Doubles + +- Preferred test doubles include dummies, fakes, stubs, and spies when the design allows. +- In special cases, use mocks sparingly (via the Moq library). +- Before overriding methods, verify the method is virtual or abstract; this applies to mocks as well. +- Never mock IMarshaller; always use a new JsonMarshaller instance.src/Savvyio.Core/Diagnostics/IAsyncHealthCheckProvider.cs (1)
10-18: Consider covariance and default CancellationToken for ergonomics.Mark T as covariant and make the token optional to match common async patterns.
- public interface IAsyncHealthCheckProvider<T> + public interface IAsyncHealthCheckProvider<out T> { /// <summary> /// Asynchronously gets the underlying target used for probing health status. /// </summary> /// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel the asynchronous operation.</param> /// <returns>A task that represents the asynchronous operation. The task result contains the target instance of type <typeparamref name="T"/> used for health probing.</returns> - Task<T> GetHealthCheckTargetAsync(CancellationToken cancellationToken); + Task<T> GetHealthCheckTargetAsync(CancellationToken cancellationToken = default); }src/Savvyio.Extensions.QueueStorage/AzureQueue.cs (1)
202-205: Access level for GetQueueServiceClient.If derived types in other assemblies need this, consider widening to protected (or protected internal). Otherwise keep internal.
-internal QueueServiceClient GetQueueServiceClient() +protected internal QueueServiceClient GetQueueServiceClient() { return _serviceClient; }.nuget/Savvyio.Extensions.QueueStorage/PackageReleaseNotes.txt (1)
1-10: Tighten wording and strip non-breaking spaces in 4.4.0 block.
- Drop “so it” for crisper bullets.
- End bullets with periods for consistency.
- Remove NBSP-only spacer lines (they trigger grammar linters and diff noise).
Version: 4.4.0 Availability: .NET 9 and .NET 8 - +# (blank line) # ALM - CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) - +# (blank line) # Improvements -- CHANGED AzureCommandQueue class in the Savvyio.Extensions.QueueStorage.Commands namespace so it now implements the IHealthCheckProvider{QueueServiceClient} interface -- CHANGED AzureEventBus class in the Savvyio.Extensions.QueueStorage.EventDriven namespace so it now implements the IHealthCheckProvider{Uri} interface +- CHANGED AzureCommandQueue class in the Savvyio.Extensions.QueueStorage.Commands namespace; it now implements the IHealthCheckProvider{QueueServiceClient} interface. +- CHANGED AzureEventBus class in the Savvyio.Extensions.QueueStorage.EventDriven namespace; it now implements the IHealthCheckProvider{Uri} interface. - +# (blank line).nuget/Savvyio.Extensions.RabbitMQ/PackageReleaseNotes.txt (1)
1-9: Minor release-note polish for 4.4.0.
- Remove NBSP-only lines.
- Tighten phrasing and add period.
Version: 4.4.0 Availability: .NET 9 and .NET 8 - +# (blank line) # ALM - CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) - +# (blank line) # Improvements -- CHANGED RabbitMqMessage class in the Savvyio.Extensions.RabbitMQ namespace so it now implements the IAsyncHealthCheckProvider{IConnection} interface +- CHANGED RabbitMqMessage class in the Savvyio.Extensions.RabbitMQ namespace; it now implements the IAsyncHealthCheckProvider{IConnection} interface..nuget/Savvyio.Extensions.SimpleQueueService/PackageReleaseNotes.txt (1)
1-10: Consistent tone/punctuation and whitespace cleanup.
- Remove NBSP-only spacer lines.
- Use concise “it now implements …” phrasing with periods.
Version: 4.4.0 Availability: .NET 9 and .NET 8 - +# (blank line) # ALM - CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) - +# (blank line) # Improvements -- CHANGED AmazonCommandQueue class in the Savvyio.Extensions.SimpleQueueService.Commands namespace so it now implements the IHealthCheckProvider{IAmazonSQS} interface -- CHANGED AmazonEventBus class in the Savvyio.Extensions.SimpleQueueService.EventDriven namespace so it now implements the IHealthCheckProvider{IAmazonSimpleNotificationService} interface +- CHANGED AmazonCommandQueue class in the Savvyio.Extensions.SimpleQueueService.Commands namespace; it now implements the IHealthCheckProvider{IAmazonSQS} interface. +- CHANGED AmazonEventBus class in the Savvyio.Extensions.SimpleQueueService.EventDriven namespace; it now implements the IHealthCheckProvider{IAmazonSimpleNotificationService} interface. - +# (blank line).nuget/Savvyio.Extensions.NATS/PackageReleaseNotes.txt (1)
1-9: Match wording to other packages and drop NBSP-only lines.
- Keep style uniform across release notes.
Version: 4.4.0 Availability: .NET 9 and .NET 8 - +# (blank line) # ALM - CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) - +# (blank line) # Improvements -- CHANGED NatsMessage class in the Savvyio.Extensions.NATS namespace so it now implements the IHealthCheckProvider{INatsConnection} interface +- CHANGED NatsMessage class in the Savvyio.Extensions.NATS namespace; it now implements the IHealthCheckProvider{INatsConnection} interface. - +# (blank line)src/Savvyio.Extensions.NATS/NatsMessage.cs (1)
55-62: Guard against use-after-dispose and document lifecycle expectations.Consider guarding or documenting that this must not be called after DisposeAsync; the returned connection may be unusable post-disposal.
- public INatsConnection GetHealthCheckTarget() - { - return NatsClient.Connection; - } + public INatsConnection GetHealthCheckTarget() + { + // Optionally guard if a disposal flag is available in AsyncDisposable. + // If not, add a brief remark in XML docs that this must not be called after disposal. + return NatsClient.Connection; + }If AsyncDisposable exposes a disposed sentinel, I can wire a precise guard; otherwise I’ll update the XML docs—let me know your preference.
src/Savvyio.Extensions.QueueStorage/Commands/AzureCommandQueue.cs (2)
57-64: Add disposal guidance to the XML docs for the returned clientClarify ownership to avoid accidental disposal of the shared QueueServiceClient.
/// <summary> /// Gets the <see cref="QueueServiceClient"/> instance used for probing the health status of the Azure Storage Queue service. /// </summary> - /// <returns>The <see cref="QueueServiceClient"/> instance representing the client connection to the Azure Storage Queue service.</returns> + /// <returns>The <see cref="QueueServiceClient"/> instance representing the client connection to the Azure Storage Queue service.</returns> + /// <remarks>The returned client is owned by this instance and must not be disposed by callers.</remarks> public QueueServiceClient GetHealthCheckTarget() { return GetQueueServiceClient(); // fetch from base class }
57-64: Consider making the base accessor protected internalCurrent call relies on an internal base member. If AzureQueue is moved to another assembly later, this breaks. Prefer protected internal (or protected) on AzureQueue.GetQueueServiceClient().
.nuget/Savvyio.Core/PackageReleaseNotes.txt (1)
1-10: Replace non‑breaking spaces with blank lines to avoid rendering quirksThere are U+00A0 lines between sections that some viewers render oddly. Use empty lines instead.
-Version: 4.4.0 -Availability: .NET 9 and .NET 8 - +Version: 4.4.0 +Availability: .NET 9 and .NET 8 + # New Features - ADDED IAsyncHealthCheckProvider interface in the Savvyio.Diagnostics namespace that defines a contract for asynchronously providing an underlying target that can be probed to assess health status - ADDED IHealthCheckProvider interface in the Savvyio.Diagnostics namespace that defines a contract for providing an underlying target that can be probed to assess health status - + # ALM - CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) - +src/Savvyio.Extensions.QueueStorage/EventDriven/AzureEventBus.cs (1)
132-139: Return the configured topic endpoint directly (avoid hardcoded /api/health)Event Grid topics don’t expose a standard “/api/health”. Returning TopicEndpoint is a safer, provider-agnostic target; let the probe decide how to test it.
- /// <summary> - /// Gets the <see cref="Uri"/> representing the health check endpoint for the configured Azure Event Grid topic. - /// </summary> - /// <returns>A <see cref="Uri"/> instance pointing to the health check endpoint of the Azure Event Grid topic.</returns> + /// <summary> + /// Gets the <see cref="Uri"/> representing the configured Azure Event Grid topic to be probed. + /// </summary> + /// <returns>A <see cref="Uri"/> instance pointing to the Azure Event Grid topic endpoint.</returns> public Uri GetHealthCheckTarget() { - return new Uri(_options.TopicEndpoint, "/api/health"); + return _options.TopicEndpoint; }src/Savvyio.Extensions.SimpleQueueService/EventDriven/AmazonEventBus.cs (1)
108-118: Document disposal responsibility for the returned SNS clientA new client is created; callers should dispose it after probing. Consider caching if probes are frequent.
/// <summary> /// Returns a new <see cref="IAmazonSimpleNotificationService"/> client instance configured for health probing of the underlying Amazon SNS service. /// </summary> - /// <returns>An <see cref="IAmazonSimpleNotificationService"/> client instance used to probe the health status of the notification service.</returns> + /// <returns>An <see cref="IAmazonSimpleNotificationService"/> client instance used to probe the health status of the notification service.</returns> + /// <remarks>The caller is responsible for disposing the returned client.</remarks> public IAmazonSimpleNotificationService GetHealthCheckTarget() { var sns = Options.ClientConfigurations.IsValid() ? new AmazonSimpleNotificationServiceClient(Options.Credentials, Options.ClientConfigurations.SimpleNotificationService()) : new AmazonSimpleNotificationServiceClient(Options.Credentials, Options.Endpoint); return sns; }src/Savvyio.Extensions.SimpleQueueService/Commands/AmazonCommandQueue.cs (1)
99-109: Document disposal responsibility for the returned SQS clientA new client is created; make it explicit that the caller must dispose it after the probe. Consider caching if probes are frequent.
/// <summary> /// Returns a new <see cref="IAmazonSQS"/> client instance configured for health probing of the underlying Amazon SQS service. /// </summary> - /// <returns>An <see cref="IAmazonSQS"/> client instance used to probe the health status of the queue service.</returns> + /// <returns>An <see cref="IAmazonSQS"/> client instance used to probe the health status of the queue service.</returns> + /// <remarks>The caller is responsible for disposing the returned client.</remarks> public IAmazonSQS GetHealthCheckTarget() { var sqs = Options.ClientConfigurations.IsValid() ? new AmazonSQSClient(Options.Credentials, Options.ClientConfigurations.SimpleQueueService()) : new AmazonSQSClient(Options.Credentials, Options.Endpoint); return sqs; }src/Savvyio.Extensions.RabbitMQ/RabbitMqMessage.cs (3)
50-50: Avoid breaking change on RabbitMqFactory setterChanging the setter to private can break derived types that previously replaced the factory (your tests already resort to reflection). Prefer keeping a protected setter or exposing an injection point.
Apply:
-protected IConnectionFactory RabbitMqFactory { get; private set; } +protected IConnectionFactory RabbitMqFactory { get; protected set; }
107-111: Reset fields after dispose to prevent accidental reuseAfter disposing, null the fields and reset the initialized flag to avoid use-after-dispose scenarios in long-lived instances.
Apply:
protected override async ValueTask OnDisposeManagedResourcesAsync() { if (RabbitMqChannel != null) { await RabbitMqChannel.DisposeAsync().ConfigureAwait(false); } if (RabbitMqConnection != null) { await RabbitMqConnection.DisposeAsync().ConfigureAwait(false); } + RabbitMqChannel = null; + RabbitMqConnection = null; + _initialized = false; }
113-121: Fix XML docs and clarify disposal responsibility for health targetMinor grammar error and unclear ownership of the returned connection when not initialized. If a new connection is created, document that the caller must dispose it to avoid leaks.
Apply:
/// <summary> -/// Asynchronously an <see cref="IConnection"/> instance used for probing the health status of the RabbitMQ broker. +/// Asynchronously retrieves an <see cref="IConnection"/> instance used for probing the health status of the RabbitMQ broker. /// </summary> /// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel the asynchronous operation.</param> -/// <returns>A task that represents the asynchronous operation. The task result contains the <see cref="IConnection"/> instance representing the active connection to the RabbitMQ broker, or a newly created connection if not already initialized.</returns> +/// <returns>A task that represents the asynchronous operation. The task result contains the <see cref="IConnection"/> representing the active connection to the RabbitMQ broker, or a newly created connection if not already initialized.</returns> +/// <remarks> +/// If the connection has not been initialized, this method creates a new connection solely for health probing. The caller is responsible for disposing that connection when done. +/// </remarks> public async Task<IConnection> GetHealthCheckTargetAsync(CancellationToken cancellationToken = default) { return RabbitMqConnection ?? await RabbitMqFactory.CreateConnectionAsync(cancellationToken).ConfigureAwait(false); }test/Savvyio.Extensions.QueueStorage.Tests/Commands/AzureCommandQueueTest.cs (3)
8-9: Remove unused usingMoq.Protected is not used.
Apply:
-using Moq.Protected;
31-41: Add invalid options ctor testWe only cover null args. Add a guard test for invalid option state to match production validators.
Apply:
[Fact] public void Constructor_ShouldThrowArgumentNullException_WhenOptionsIsNull() { Assert.Throws<ArgumentNullException>(() => new AzureCommandQueue(_marshallerMock.Object, null)); } + +[Fact] +public void Constructor_ShouldThrowArgumentException_WhenOptionsAreInvalid() +{ + var invalid = new AzureQueueOptions(); // missing required fields + Assert.Throws<ArgumentException>(() => new AzureCommandQueue(_marshallerMock.Object, invalid)); +}
50-63: Strengthen SendAsync test to cover null messagesAdd a null-argument test; current test with empty list is fine but weak.
Apply:
[Fact] public async Task SendAsync_ShouldReturnTask() { @@ Assert.NotNull(task); await task; // Ensure it completes without exception } + +[Fact] +public async Task SendAsync_ShouldThrowArgumentNullException_WhenMessagesIsNull() +{ + var queue = new AzureCommandQueue(_marshallerMock.Object, _options); + await Assert.ThrowsAsync<ArgumentNullException>(() => queue.SendAsync(null)); +}test/Savvyio.Extensions.SimpleQueueService.Tests/Commands/AmazonCommandQueueTest.cs (3)
7-15: Trim unused usingsThese namespaces are unused.
Apply:
-using Amazon.SQS.Model; -using Cuemon.Extensions; -using Cuemon.Extensions.Reflection;
66-78: Rename to reflect actual assertion or verify call properlyThe method name implies verifying an SQS retrieval call, but the test only checks the return type. Either rename or inject a mock IAmazonSQS to assert the call.
Apply (rename):
-[Fact] -public async Task ReceiveAsync_Should_Call_RetrieveMessagesAsync() +[Fact] +public async Task ReceiveAsync_Should_Return_AsyncEnumerable()
80-89: Dispose health-check client to avoid resource leak in testsIAmazonSQS is IDisposable; dispose it after assertions.
Apply:
[Fact] public void GetHealthCheckTarget_Should_Return_IAmazonSQS_Instance() { var sut = new AmazonCommandQueue(_marshaller, _options); - var sqs = sut.GetHealthCheckTarget(); + var sqs = sut.GetHealthCheckTarget(); Assert.NotNull(sqs); Assert.IsAssignableFrom<IAmazonSQS>(sqs); + sqs.Dispose(); }test/Savvyio.Extensions.RabbitMQ.Tests/RabbitMqMessageTest.cs (4)
2-2: Remove unused usingCuemon.Reflection is not used.
Apply:
-using Cuemon.Reflection;
41-45: Ensure options validity so the intended exception is assertedConstructor validates options before marshaller. To reliably assert ArgumentNullException for marshaller, provide a valid options instance.
Apply:
[Fact] public void Constructor_Throws_WhenMarshallerIsNull() { - var options = new RabbitMqMessageOptions(); + var options = new RabbitMqMessageOptions { AmqpUrl = new Uri("amqp://localhost:5672") }; Assert.Throws<ArgumentNullException>(() => new TestRabbitMqMessage(null, options)); }
126-139: Dispose health-check connection created by test to avoid leaksIf the connection is a mock, no-op; if real, ensure disposal.
Apply:
var result = await sut.GetHealthCheckTargetAsync(); Assert.Same(connectionMock, result); +if (result is IAsyncDisposable ad) { await ad.DisposeAsync(); } else { (result as IDisposable)?.Dispose(); }
141-162: Avoid reflection to set RabbitMqFactory in tests if possibleReflection against protected members is brittle. Consider exposing a protected constructor on the test double that accepts an IConnectionFactory, or add an overridable factory method in the base.
Example (test-only):
private class TestRabbitMqMessage : RabbitMqMessage { public TestRabbitMqMessage(IMarshaller m, RabbitMqMessageOptions o, IConnectionFactory f = null) : base(m, o) { if (f != null) RabbitMqFactory = f; // requires protected setter in production } }test/Savvyio.Extensions.SimpleQueueService.Tests/EventDriven/AmazonEventBusTest.cs (2)
56-63: Strengthen assertion by validating the offending parameter.Asserting ParamName (or message) makes the guard more precise and prevents false positives if multiple guards throw ArgumentException.
Apply:
-Assert.Throws<ArgumentException>(() => new AmazonEventBus(marshaller, options)); +var ex = Assert.Throws<ArgumentException>(() => new AmazonEventBus(marshaller, options)); +Assert.Contains("Options", ex.ParamName ?? ex.Message, StringComparison.OrdinalIgnoreCase);
65-82: Dispose the AWS client and assert region to harden the test.Dispose to avoid handle leaks, and assert RegionEndpoint to ensure options are honored.
Apply:
- var sns = sut.GetHealthCheckTarget(); - - Assert.NotNull(sns); - Assert.IsAssignableFrom<IAmazonSimpleNotificationService>(sns); + using var sns = sut.GetHealthCheckTarget(); + Assert.NotNull(sns); + Assert.IsAssignableFrom<IAmazonSimpleNotificationService>(sns); + Assert.Equal(RegionEndpoint.EUWest1.SystemName, (sns as AmazonSimpleNotificationServiceClient)?.Config.RegionEndpoint?.SystemName);test/Savvyio.Extensions.NATS.Tests/NatsMessageTest.cs (3)
14-21: Limit test helper surface: make FakeMarshaller internal and sealed.Keeps helpers out of the public API of the test assembly; no functional change.
Apply:
- public class FakeMarshaller : IMarshaller + internal sealed class FakeMarshaller : IMarshaller
23-38: Limit test helper surface: make TestNatsMessage internal and sealed.Same rationale; also keeps derivation stable.
Apply:
- public class TestNatsMessage : NatsMessage + internal sealed class TestNatsMessage : NatsMessage
70-76: Tighten invalid-options assertion.Verify parameter identity for clearer intent and resilience to additional guards.
Apply:
- Assert.Throws<ArgumentException>(() => new TestNatsMessage(marshaller, options)); + var ex = Assert.Throws<ArgumentException>(() => new TestNatsMessage(marshaller, options)); + Assert.Contains("Subject", ex.ParamName ?? ex.Message, StringComparison.OrdinalIgnoreCase);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (56)
.github/copilot-instructions.md(1 hunks).nuget/Savvyio.App/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Commands.Messaging/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Commands/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Core/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Domain.EventSourcing/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Domain/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.EventDriven.Messaging/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.EventDriven/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Extensions.Dapper/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Extensions.DapperExtensions/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Extensions.DependencyInjection.Dapper/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Extensions.DependencyInjection.DapperExtensions/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Extensions.DependencyInjection.Domain/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Extensions.DependencyInjection.EFCore.Domain.EventSourcing/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Extensions.DependencyInjection.EFCore.Domain/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Extensions.DependencyInjection.EFCore/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Extensions.DependencyInjection.NATS/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Extensions.DependencyInjection.Newtonsoft.Json/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Extensions.DependencyInjection.QueueStorage/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Extensions.DependencyInjection.RabbitMQ/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Extensions.DependencyInjection.SimpleQueueService/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Extensions.DependencyInjection.Text.Json/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Extensions.DependencyInjection/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Extensions.Dispatchers/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Extensions.EFCore.Domain.EventSourcing/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Extensions.EFCore.Domain/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Extensions.EFCore/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Extensions.NATS/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Extensions.Newtonsoft.Json/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Extensions.QueueStorage/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Extensions.RabbitMQ/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Extensions.SimpleQueueService/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Extensions.Text.Json/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Messaging/PackageReleaseNotes.txt(1 hunks).nuget/Savvyio.Queries/PackageReleaseNotes.txt(1 hunks)Directory.Packages.props(1 hunks)README.md(1 hunks)src/Savvyio.Core/Diagnostics/IAsyncHealthCheckProvider.cs(1 hunks)src/Savvyio.Core/Diagnostics/IHealthCheckProvider.cs(1 hunks)src/Savvyio.Extensions.NATS/NatsMessage.cs(2 hunks)src/Savvyio.Extensions.QueueStorage/AzureQueue.cs(3 hunks)src/Savvyio.Extensions.QueueStorage/Commands/AzureCommandQueue.cs(2 hunks)src/Savvyio.Extensions.QueueStorage/EventDriven/AzureEventBus.cs(5 hunks)src/Savvyio.Extensions.RabbitMQ/RabbitMqMessage.cs(3 hunks)src/Savvyio.Extensions.SimpleQueueService/Commands/AmazonCommandQueue.cs(3 hunks)src/Savvyio.Extensions.SimpleQueueService/EventDriven/AmazonEventBus.cs(3 hunks)test/Savvyio.Extensions.NATS.Tests/NatsMessageTest.cs(1 hunks)test/Savvyio.Extensions.QueueStorage.Tests/Commands/AzureCommandQueueTest.cs(1 hunks)test/Savvyio.Extensions.QueueStorage.Tests/EventDriven/AzureEventBusTest.cs(1 hunks)test/Savvyio.Extensions.QueueStorage.Tests/Savvyio.Extensions.QueueStorage.Tests.csproj(1 hunks)test/Savvyio.Extensions.RabbitMQ.Tests/RabbitMqMessageTest.cs(1 hunks)test/Savvyio.Extensions.RabbitMQ.Tests/Savvyio.Extensions.RabbitMQ.Tests.csproj(1 hunks)test/Savvyio.Extensions.SimpleQueueService.Tests/Commands/AmazonCommandQueueTest.cs(1 hunks)test/Savvyio.Extensions.SimpleQueueService.Tests/EventDriven/AmazonEventBusTest.cs(1 hunks)test/Savvyio.Extensions.SimpleQueueService.Tests/Savvyio.Extensions.SimpleQueueService.Tests.csproj(1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.cs
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.cs: Use the same XML documentation style as found throughout the codebase
Add XML documentation comments to public and protected classes and methods where appropriate
Files:
src/Savvyio.Extensions.NATS/NatsMessage.cstest/Savvyio.Extensions.QueueStorage.Tests/Commands/AzureCommandQueueTest.cssrc/Savvyio.Core/Diagnostics/IHealthCheckProvider.cssrc/Savvyio.Core/Diagnostics/IAsyncHealthCheckProvider.cssrc/Savvyio.Extensions.QueueStorage/Commands/AzureCommandQueue.cstest/Savvyio.Extensions.RabbitMQ.Tests/RabbitMqMessageTest.cssrc/Savvyio.Extensions.SimpleQueueService/Commands/AmazonCommandQueue.cssrc/Savvyio.Extensions.SimpleQueueService/EventDriven/AmazonEventBus.cstest/Savvyio.Extensions.SimpleQueueService.Tests/EventDriven/AmazonEventBusTest.cstest/Savvyio.Extensions.SimpleQueueService.Tests/Commands/AmazonCommandQueueTest.cssrc/Savvyio.Extensions.QueueStorage/EventDriven/AzureEventBus.cstest/Savvyio.Extensions.NATS.Tests/NatsMessageTest.cssrc/Savvyio.Extensions.RabbitMQ/RabbitMqMessage.cstest/Savvyio.Extensions.QueueStorage.Tests/EventDriven/AzureEventBusTest.cssrc/Savvyio.Extensions.QueueStorage/AzureQueue.cs
**/*.Tests.csproj
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Unit tests for a Savvyio.Foo assembly must live in a Savvyio.Foo.Tests assembly (project naming)
Files:
test/Savvyio.Extensions.RabbitMQ.Tests/Savvyio.Extensions.RabbitMQ.Tests.csprojtest/Savvyio.Extensions.SimpleQueueService.Tests/Savvyio.Extensions.SimpleQueueService.Tests.csprojtest/Savvyio.Extensions.QueueStorage.Tests/Savvyio.Extensions.QueueStorage.Tests.csproj
**/*.@(Tests|FunctionalTests).csproj
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
In test projects, override the RootNamespace to match the source assembly namespace (e.g., Savvyio.Foo)
Files:
test/Savvyio.Extensions.RabbitMQ.Tests/Savvyio.Extensions.RabbitMQ.Tests.csprojtest/Savvyio.Extensions.SimpleQueueService.Tests/Savvyio.Extensions.SimpleQueueService.Tests.csprojtest/Savvyio.Extensions.QueueStorage.Tests/Savvyio.Extensions.QueueStorage.Tests.csproj
{**/{test,tests}/**/*.cs,**/*.@(Tests|FunctionalTests)/**/*.cs}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
{**/{test,tests}/**/*.cs,**/*.@(Tests|FunctionalTests)/**/*.cs}: Always inherit from the Codebelt.Extensions.Xunit Test base class for all unit test classes
Use [Fact] for standard unit tests
Use [Theory] with [InlineData] or other data sources for parameterized tests
Test methods should use descriptive names that state the expected behavior (e.g., ShouldReturnTrue_WhenConditionIsMet)
Use xUnit Assert methods for all assertions
Prefer explicit and expressive assertions (e.g., Assert.Equal, Assert.NotNull, Assert.Contains)
Use namespaces in tests that mirror the source code structure and match the class under test
Keep tests focused and isolated
Do not rely on external systems in tests except xUnit and Codebelt.Extensions.Xunit (and derivations)
Ensure tests are deterministic and repeatable
Files:
test/Savvyio.Extensions.QueueStorage.Tests/Commands/AzureCommandQueueTest.cstest/Savvyio.Extensions.RabbitMQ.Tests/RabbitMqMessageTest.cstest/Savvyio.Extensions.SimpleQueueService.Tests/EventDriven/AmazonEventBusTest.cstest/Savvyio.Extensions.SimpleQueueService.Tests/Commands/AmazonCommandQueueTest.cstest/Savvyio.Extensions.NATS.Tests/NatsMessageTest.cstest/Savvyio.Extensions.QueueStorage.Tests/EventDriven/AzureEventBusTest.cs
**/{test,tests}/**/*Test.cs
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Test classes must end with the suffix 'Test' (e.g., CommandDispatcherTest)
Files:
test/Savvyio.Extensions.QueueStorage.Tests/Commands/AzureCommandQueueTest.cstest/Savvyio.Extensions.RabbitMQ.Tests/RabbitMqMessageTest.cstest/Savvyio.Extensions.SimpleQueueService.Tests/EventDriven/AmazonEventBusTest.cstest/Savvyio.Extensions.SimpleQueueService.Tests/Commands/AmazonCommandQueueTest.cstest/Savvyio.Extensions.NATS.Tests/NatsMessageTest.cstest/Savvyio.Extensions.QueueStorage.Tests/EventDriven/AzureEventBusTest.cs
🧠 Learnings (10)
📚 Learning: 2025-08-29T22:04:48.072Z
Learnt from: CR
PR: codebeltnet/savvyio#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-29T22:04:48.072Z
Learning: Applies to **/*.Tests.csproj : Unit tests for a Savvyio.Foo assembly must live in a Savvyio.Foo.Tests assembly (project naming)
Applied to files:
test/Savvyio.Extensions.RabbitMQ.Tests/Savvyio.Extensions.RabbitMQ.Tests.csprojtest/Savvyio.Extensions.SimpleQueueService.Tests/Savvyio.Extensions.SimpleQueueService.Tests.csprojtest/Savvyio.Extensions.QueueStorage.Tests/Savvyio.Extensions.QueueStorage.Tests.csproj
📚 Learning: 2025-08-29T22:04:48.072Z
Learnt from: CR
PR: codebeltnet/savvyio#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-29T22:04:48.072Z
Learning: Applies to **/*.@(Tests|FunctionalTests).csproj : In test projects, override the RootNamespace to match the source assembly namespace (e.g., <RootNamespace>Savvyio.Foo</RootNamespace>)
Applied to files:
test/Savvyio.Extensions.RabbitMQ.Tests/Savvyio.Extensions.RabbitMQ.Tests.csproj
📚 Learning: 2025-08-29T22:04:48.072Z
Learnt from: CR
PR: codebeltnet/savvyio#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-29T22:04:48.072Z
Learning: Applies to {**/{test,tests}/**/*.cs,**/*.@(Tests|FunctionalTests)/**/*.cs} : Do not rely on external systems in tests except xUnit and Codebelt.Extensions.Xunit (and derivations)
Applied to files:
.github/copilot-instructions.md
📚 Learning: 2025-08-29T22:04:48.072Z
Learnt from: CR
PR: codebeltnet/savvyio#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-29T22:04:48.072Z
Learning: Applies to {**/{test,tests}/**/*.cs,**/*.@(Tests|FunctionalTests)/**/*.cs} : Always inherit from the Codebelt.Extensions.Xunit Test base class for all unit test classes
Applied to files:
.github/copilot-instructions.md
📚 Learning: 2025-08-29T22:04:48.072Z
Learnt from: CR
PR: codebeltnet/savvyio#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-29T22:04:48.072Z
Learning: Applies to {**/{test,tests}/**/*.cs,**/*.@(Tests|FunctionalTests)/**/*.cs} : Ensure tests are deterministic and repeatable
Applied to files:
.github/copilot-instructions.md
📚 Learning: 2025-08-29T22:04:48.072Z
Learnt from: CR
PR: codebeltnet/savvyio#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-29T22:04:48.072Z
Learning: Applies to {**/{test,tests}/**/*.cs,**/*.@(Tests|FunctionalTests)/**/*.cs} : Keep tests focused and isolated
Applied to files:
.github/copilot-instructions.md
📚 Learning: 2025-08-29T22:04:48.072Z
Learnt from: CR
PR: codebeltnet/savvyio#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-29T22:04:48.072Z
Learning: Applies to {**/{test,tests}/**/*.cs,**/*.@(Tests|FunctionalTests)/**/*.cs} : Use [Fact] for standard unit tests
Applied to files:
.github/copilot-instructions.md
📚 Learning: 2025-08-29T22:04:48.072Z
Learnt from: CR
PR: codebeltnet/savvyio#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-29T22:04:48.072Z
Learning: Applies to {**/{test,tests}/**/*.cs,**/*.@(Tests|FunctionalTests)/**/*.cs} : Prefer explicit and expressive assertions (e.g., Assert.Equal, Assert.NotNull, Assert.Contains)
Applied to files:
.github/copilot-instructions.md
📚 Learning: 2025-08-29T22:04:48.072Z
Learnt from: CR
PR: codebeltnet/savvyio#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-29T22:04:48.072Z
Learning: Applies to {**/{test,tests}/**/*.cs,**/*.@(Tests|FunctionalTests)/**/*.cs} : Use xUnit Assert methods for all assertions
Applied to files:
.github/copilot-instructions.md
📚 Learning: 2025-08-29T22:04:48.072Z
Learnt from: CR
PR: codebeltnet/savvyio#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-29T22:04:48.072Z
Learning: Applies to {**/{test,tests}/**/*.cs,**/*.@(Tests|FunctionalTests)/**/*.cs} : Use namespaces in tests that mirror the source code structure and match the class under test
Applied to files:
.github/copilot-instructions.md
🧬 Code graph analysis (11)
test/Savvyio.Extensions.QueueStorage.Tests/Commands/AzureCommandQueueTest.cs (2)
test/Savvyio.Extensions.NATS.Tests/NatsMessageTest.cs (6)
Fact(44-54)Fact(56-61)Fact(63-68)Fact(70-76)Fact(78-89)Fact(91-104)test/Savvyio.Extensions.RabbitMQ.Tests/RabbitMqMessageTest.cs (3)
Fact(40-45)Fact(47-52)Fact(54-64)
src/Savvyio.Core/Diagnostics/IAsyncHealthCheckProvider.cs (1)
src/Savvyio.Core/Diagnostics/IHealthCheckProvider.cs (1)
T(13-13)
src/Savvyio.Extensions.QueueStorage/Commands/AzureCommandQueue.cs (1)
src/Savvyio.Extensions.QueueStorage/AzureQueue.cs (3)
AzureQueue(20-206)AzureQueue(98-132)QueueServiceClient(202-205)
test/Savvyio.Extensions.RabbitMQ.Tests/RabbitMqMessageTest.cs (1)
test/Savvyio.Extensions.NATS.Tests/NatsMessageTest.cs (7)
Task(30-33)Fact(44-54)Fact(56-61)Fact(63-68)Fact(70-76)Fact(78-89)Fact(91-104)
test/Savvyio.Extensions.SimpleQueueService.Tests/EventDriven/AmazonEventBusTest.cs (1)
src/Savvyio.Extensions.SimpleQueueService/EventDriven/AmazonEventBus.cs (1)
IAmazonSimpleNotificationService(112-118)
test/Savvyio.Extensions.SimpleQueueService.Tests/Commands/AmazonCommandQueueTest.cs (1)
src/Savvyio.Extensions.SimpleQueueService/Commands/AmazonCommandQueue.cs (1)
IAmazonSQS(103-109)
src/Savvyio.Extensions.QueueStorage/EventDriven/AzureEventBus.cs (3)
src/Savvyio.Extensions.DependencyInjection.QueueStorage/EventDriven/AzureEventBus.cs (2)
AzureEventBus(13-31)AzureEventBus(28-30)src/Savvyio.Extensions.QueueStorage/AzureQueue.cs (2)
AzureQueue(20-206)AzureQueue(98-132)src/Savvyio.Extensions.QueueStorage/EventDriven/AzureEventBusOptions.cs (2)
AzureEventBusOptions(14-124)AzureEventBusOptions(48-52)
test/Savvyio.Extensions.NATS.Tests/NatsMessageTest.cs (2)
test/Savvyio.Extensions.RabbitMQ.Tests/RabbitMqMessageTest.cs (3)
Fact(40-45)Fact(47-52)Fact(54-64)test/Savvyio.Extensions.QueueStorage.Tests/Commands/AzureCommandQueueTest.cs (6)
Fact(31-35)Fact(37-41)Fact(43-48)Fact(50-63)Fact(65-77)Fact(79-91)
src/Savvyio.Extensions.RabbitMQ/RabbitMqMessage.cs (2)
src/Savvyio.Extensions.RabbitMQ/Commands/RabbitMqCommandQueue.cs (2)
Task(51-70)Task(115-122)src/Savvyio.Extensions.RabbitMQ/EventDriven/RabbitMqEventBus.cs (2)
Task(51-67)Task(75-108)
test/Savvyio.Extensions.QueueStorage.Tests/EventDriven/AzureEventBusTest.cs (1)
src/Savvyio.Extensions.QueueStorage/EventDriven/AzureEventBus.cs (1)
Uri(136-139)
src/Savvyio.Extensions.QueueStorage/AzureQueue.cs (1)
src/Savvyio.Extensions.QueueStorage/Commands/AzureCommandQueue.cs (1)
QueueServiceClient(61-64)
🪛 LanguageTool
.nuget/Savvyio.Extensions.QueueStorage/PackageReleaseNotes.txt
[grammar] ~1-~1: There might be a mistake here.
Context: Version: 4.4.0 Availability: .NET 9 and .NET 8 # ALM ...
(QB_NEW_EN)
[grammar] ~4-~4: There might be a mistake here.
Context: ... Availability: .NET 9 and .NET 8 # ALM - CHANGED Dependencies have been upgraded ...
(QB_NEW_EN)
[grammar] ~7-~7: There might be a mistake here.
Context: ...arget frameworks (TFMs) # Improvements - CHANGED AzureCommandQueue class in the S...
(QB_NEW_EN)
.github/copilot-instructions.md
[grammar] ~113-~113: There might be a mistake here.
Context: ... spies if and when the design allows it. - Under special circumstances, mock can be...
(QB_NEW_EN)
[grammar] ~114-~114: There might be a mistake here.
Context: ...pecial circumstances, mock can be used (using Moq library). - Before overriding metho...
(QB_NEW_EN)
[grammar] ~114-~114: There might be a mistake here.
Context: ...s, mock can be used (using Moq library). - Before overriding methods, verify that t...
(QB_NEW_EN)
.nuget/Savvyio.Core/PackageReleaseNotes.txt
[grammar] ~1-~1: There might be a mistake here.
Context: Version: 4.4.0 Availability: .NET 9 and .NET 8 # New ...
(QB_NEW_EN)
[grammar] ~4-~4: There might be a mistake here.
Context: ...lity: .NET 9 and .NET 8 # New Features - ADDED IAsyncHealthCheckProvider interfac...
(QB_NEW_EN)
.nuget/Savvyio.Extensions.SimpleQueueService/PackageReleaseNotes.txt
[grammar] ~1-~1: There might be a mistake here.
Context: Version: 4.4.0 Availability: .NET 9 and .NET 8 # ALM ...
(QB_NEW_EN)
[grammar] ~4-~4: There might be a mistake here.
Context: ... Availability: .NET 9 and .NET 8 # ALM - CHANGED Dependencies have been upgraded ...
(QB_NEW_EN)
[grammar] ~7-~7: There might be a mistake here.
Context: ...arget frameworks (TFMs) # Improvements - CHANGED AmazonCommandQueue class in the ...
(QB_NEW_EN)
.nuget/Savvyio.App/PackageReleaseNotes.txt
[locale-violation] ~1-~1: Possible error ortogràfic. «Version» és correcte com a forma balear (1a personal singular, present d’indicatiu).
Context: Version: 4.4.0 Availability: .NET 9 and .NET 8 ...
(EXIGEIX_VERBS_CENTRAL)
[duplication] ~5-~5: Possible error: heu repetit una paraula
Context: ...ity: .NET 9 and .NET 8 # References - Savvyio - Savvyio.Commands - Savvyio.Commands.Messaging -...
(CATALAN_WORD_REPEAT_RULE)
[grammar] ~34-~34: Paraula desconeguda com a nom propi.
Context: ...- Savvyio.Messaging - Savvyio.Queries Version: 4.3.0 Availability: .NET 9 and .NET 8 ...
(VERBS_NOMSPROPIS)
.nuget/Savvyio.Extensions.DependencyInjection.NATS/PackageReleaseNotes.txt
[grammar] ~1-~1: There might be a mistake here.
Context: Version: 4.4.0 Availability: .NET 9 and .NET 8 # ALM ...
(QB_NEW_EN)
[grammar] ~2-~2: There might be a mistake here.
Context: ...n: 4.4.0 Availability: .NET 9 and .NET 8 # ALM - CHANGED Dependencies have been upg...
(QB_NEW_EN)
[grammar] ~4-~4: There might be a mistake here.
Context: ... Availability: .NET 9 and .NET 8 # ALM - CHANGED Dependencies have been upgraded ...
(QB_NEW_EN)
README.md
[grammar] ~21-~21: There might be a mistake here.
Context: ...Core, - Marshaller for System.Text.Json, - Marshaller for Newtonsoft.Json, - AWS SN...
(QB_NEW_EN)
[grammar] ~22-~22: There might be a mistake here.
Context: ....Json, - Marshaller for Newtonsoft.Json, - AWS SNS/SQS, - Azure Queue Storage/Event...
(QB_NEW_EN)
[grammar] ~23-~23: There might be a mistake here.
Context: ...ller for Newtonsoft.Json, - AWS SNS/SQS, - Azure Queue Storage/Event Grid, - Rabbi...
(QB_NEW_EN)
[grammar] ~24-~24: There might be a mistake here.
Context: ...S/SQS, - Azure Queue Storage/Event Grid, - RabbitMQ, - NATS. ## State of the Union...
(QB_NEW_EN)
[grammar] ~25-~25: There might be a mistake here.
Context: ...e Queue Storage/Event Grid, - RabbitMQ, - NATS. ## State of the Union Support fo...
(QB_NEW_EN)
[grammar] ~32-~32: There might be a mistake here.
Context: .../endoflife.date/dotnet). > [!IMPORTANT] > Version 2.2.0 of Savvy I/O will be the...
(QB_NEW_EN)
[grammar] ~33-~33: There might be a mistake here.
Context: ...the last version to support .NET 7.
> Version 3.0.0 of Savvy I/O will be the...
(QB_NEW_EN)
.nuget/Savvyio.Extensions.RabbitMQ/PackageReleaseNotes.txt
[grammar] ~1-~1: There might be a mistake here.
Context: Version: 4.4.0 Availability: .NET 9 and .NET 8 # ALM ...
(QB_NEW_EN)
[grammar] ~4-~4: There might be a mistake here.
Context: ... Availability: .NET 9 and .NET 8 # ALM - CHANGED Dependencies have been upgraded ...
(QB_NEW_EN)
[grammar] ~7-~7: There might be a mistake here.
Context: ...arget frameworks (TFMs) # Improvements - CHANGED RabbitMqMessage class in the Sav...
(QB_NEW_EN)
.nuget/Savvyio.Extensions.DependencyInjection.Text.Json/PackageReleaseNotes.txt
[grammar] ~1-~1: There might be a mistake here.
Context: Version: 4.4.0 Availability: .NET 9 and .NET 8 # ALM ...
(QB_NEW_EN)
[grammar] ~4-~4: There might be a mistake here.
Context: ... Availability: .NET 9 and .NET 8 # ALM - CHANGED Dependencies have been upgraded ...
(QB_NEW_EN)
.nuget/Savvyio.Extensions.DependencyInjection.Newtonsoft.Json/PackageReleaseNotes.txt
[grammar] ~1-~1: There might be a mistake here.
Context: Version: 4.4.0 Availability: .NET 9 and .NET 8 # ALM ...
(QB_NEW_EN)
[grammar] ~2-~2: There might be a mistake here.
Context: ...n: 4.4.0 Availability: .NET 9 and .NET 8 # ALM - CHANGED Dependencies have been upg...
(QB_NEW_EN)
[grammar] ~4-~4: There might be a mistake here.
Context: ... Availability: .NET 9 and .NET 8 # ALM - CHANGED Dependencies have been upgraded ...
(QB_NEW_EN)
.nuget/Savvyio.Extensions.NATS/PackageReleaseNotes.txt
[grammar] ~1-~1: There might be a mistake here.
Context: Version: 4.4.0 Availability: .NET 9 and .NET 8 # ALM ...
(QB_NEW_EN)
[grammar] ~4-~4: There might be a mistake here.
Context: ... Availability: .NET 9 and .NET 8 # ALM - CHANGED Dependencies have been upgraded ...
(QB_NEW_EN)
[grammar] ~7-~7: There might be a mistake here.
Context: ...arget frameworks (TFMs) # Improvements - CHANGED NatsMessage class in the Savvyio...
(QB_NEW_EN)
| var queueUri = $"https://{options.StorageAccountName}.queue.core.windows.net/{options.QueueName}".ToUri(); | ||
| if (options.Credential != null) | ||
| { | ||
| _client = new QueueClient(queueUri, options.Credential, options.Settings); | ||
| _serviceClient = new QueueServiceClient(queueUri, options.Credential, options.Settings); | ||
| } | ||
| else if (options.SasCredential != null) | ||
| { | ||
| _client = new QueueClient(queueUri, options.SasCredential, options.Settings); | ||
| _serviceClient = new QueueServiceClient(queueUri, options.SasCredential, options.Settings); | ||
| } | ||
| else if (options.StorageKeyCredential != null) | ||
| { | ||
| _client = new QueueClient(queueUri, options.StorageKeyCredential, options.Settings); | ||
| _serviceClient = new QueueServiceClient(queueUri, options.StorageKeyCredential, options.Settings); | ||
| } | ||
| } | ||
| else | ||
| { | ||
| _client = new QueueClient(options.ConnectionString, options.QueueName, options.Settings); | ||
| _serviceClient = new QueueServiceClient(options.ConnectionString, options.Settings); | ||
| } | ||
|
|
||
| _client = _serviceClient!.GetQueueClient(options.QueueName); |
There was a problem hiding this comment.
Bug: QueueServiceClient is constructed with a queue-specific URI (doubles the queue segment).
QueueServiceClient should point to the service endpoint, not the queue URI. Current code produces …/{queue}/{queue}. Fix by using the service endpoint and then deriving the queue client.
- var queueUri = $"https://{options.StorageAccountName}.queue.core.windows.net/{options.QueueName}".ToUri();
+ var serviceUri = $"https://{options.StorageAccountName}.queue.core.windows.net".ToUri();
if (options.Credential != null)
{
- _serviceClient = new QueueServiceClient(queueUri, options.Credential, options.Settings);
+ _serviceClient = new QueueServiceClient(serviceUri, options.Credential, options.Settings);
}
else if (options.SasCredential != null)
{
- _serviceClient = new QueueServiceClient(queueUri, options.SasCredential, options.Settings);
+ _serviceClient = new QueueServiceClient(serviceUri, options.SasCredential, options.Settings);
}
else if (options.StorageKeyCredential != null)
{
- _serviceClient = new QueueServiceClient(queueUri, options.StorageKeyCredential, options.Settings);
+ _serviceClient = new QueueServiceClient(serviceUri, options.StorageKeyCredential, options.Settings);
}
+ else
+ {
+ throw new InvalidOperationException("AzureQueueOptions must provide either ConnectionString or one of Credential, SasCredential, or StorageKeyCredential.");
+ }
@@
- _client = _serviceClient!.GetQueueClient(options.QueueName);
+ _client = _serviceClient.GetQueueClient(options.QueueName);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| var queueUri = $"https://{options.StorageAccountName}.queue.core.windows.net/{options.QueueName}".ToUri(); | |
| if (options.Credential != null) | |
| { | |
| _client = new QueueClient(queueUri, options.Credential, options.Settings); | |
| _serviceClient = new QueueServiceClient(queueUri, options.Credential, options.Settings); | |
| } | |
| else if (options.SasCredential != null) | |
| { | |
| _client = new QueueClient(queueUri, options.SasCredential, options.Settings); | |
| _serviceClient = new QueueServiceClient(queueUri, options.SasCredential, options.Settings); | |
| } | |
| else if (options.StorageKeyCredential != null) | |
| { | |
| _client = new QueueClient(queueUri, options.StorageKeyCredential, options.Settings); | |
| _serviceClient = new QueueServiceClient(queueUri, options.StorageKeyCredential, options.Settings); | |
| } | |
| } | |
| else | |
| { | |
| _client = new QueueClient(options.ConnectionString, options.QueueName, options.Settings); | |
| _serviceClient = new QueueServiceClient(options.ConnectionString, options.Settings); | |
| } | |
| _client = _serviceClient!.GetQueueClient(options.QueueName); | |
| var serviceUri = $"https://{options.StorageAccountName}.queue.core.windows.net".ToUri(); | |
| if (options.Credential != null) | |
| { | |
| _serviceClient = new QueueServiceClient(serviceUri, options.Credential, options.Settings); | |
| } | |
| else if (options.SasCredential != null) | |
| { | |
| _serviceClient = new QueueServiceClient(serviceUri, options.SasCredential, options.Settings); | |
| } | |
| else if (options.StorageKeyCredential != null) | |
| { | |
| _serviceClient = new QueueServiceClient(serviceUri, options.StorageKeyCredential, options.Settings); | |
| } | |
| else | |
| { | |
| throw new InvalidOperationException("AzureQueueOptions must provide either ConnectionString or one of Credential, SasCredential, or StorageKeyCredential."); | |
| } | |
| } | |
| else | |
| { | |
| _serviceClient = new QueueServiceClient(options.ConnectionString, options.Settings); | |
| } | |
| _client = _serviceClient.GetQueueClient(options.QueueName); |
| var eventGridClient = new Mock<EventGridPublisherClient>(); | ||
| eventGridClient | ||
| .Setup(c => c.SendEventAsync(It.IsAny<Azure.Messaging.CloudEvent>(), It.IsAny<CancellationToken>())) | ||
| .ReturnsAsync(Mock.Of<Azure.Response>()) | ||
| .Verifiable(); | ||
|
|
||
| var bus = CreateSut(marshaller: marshaller); | ||
| SetPrivateClient(bus, eventGridClient.Object); | ||
|
|
There was a problem hiding this comment.
Same Moq ctor fix in signature test
Replicate the constructor-args fix here.
Apply:
-var eventGridClient = new Mock<EventGridPublisherClient>();
+var eventGridClient = new Mock<EventGridPublisherClient>(
+ new Uri("https://test.topic"),
+ new AzureKeyCredential("dummy"));🤖 Prompt for AI Agents
In test/Savvyio.Extensions.QueueStorage.Tests/EventDriven/AzureEventBusTest.cs
around lines 98 to 106, the Mock<EventGridPublisherClient>() instantiation fails
because the real EventGridPublisherClient requires constructor arguments;
replace the parameterless Mock creation with a Mock constructed the same way as
in the related signature test — either use Mock.Of<EventGridPublisherClient>()
to create a proxy without calling a constructor, or instantiate new
Mock<EventGridPublisherClient>(MockBehavior.Default, /* supply the same
constructor args used elsewhere or the test fixture values */) and then apply
the same Setup/Returns/Verifiable calls and SetPrivateClient call as before.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #39 +/- ##
==========================================
+ Coverage 74.97% 77.82% +2.84%
==========================================
Files 177 177
Lines 3681 3711 +30
Branches 362 365 +3
==========================================
+ Hits 2760 2888 +128
+ Misses 919 821 -98
Partials 2 2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|



This pull request prepares the Savvyio suite for version 4.4.0, introducing new health check interfaces and upgrading dependencies across many packages to ensure compatibility with .NET 8 and .NET 9. It also updates internal documentation with preferred practices for writing test doubles.
Release and Dependency Upgrades:
New Features:
IAsyncHealthCheckProviderandIHealthCheckProviderinterfaces in theSavvyio.Diagnosticsnamespace to provide contracts for health status probing, supporting both synchronous and asynchronous scenarios.Documentation and Testing Guidelines:
.github/copilot-instructions.md, specifying when to use dummies, fakes, stubs, spies, and mocks, and clarifying rules for mocking and marshaller usage.Summary by CodeRabbit
New Features
Documentation
Tests
Chores