Skip to content

Conversation

@gimlichael
Copy link
Member

@gimlichael gimlichael commented Sep 11, 2025

Summary

  • Add missing unit tests for SQS client configuration, ARN conversion, visibility timeout clamping
  • Cover edge cases for NATS command queue heartbeat override
  • Verify RabbitMQ connectivity initialization is thread-safe

Testing

  • for proj in $(find test -name '*.csproj' | grep -v FunctionalTests); do dotnet test $proj; done

https://chatgpt.com/codex/tasks/task_e_68c1e1e6cc5c83308a173cdc61ea3b36

Summary by CodeRabbit

  • Tests
    • Expanded coverage across messaging integrations.
      • NATS: Confirms heartbeat can be overridden after expiry settings.
      • RabbitMQ: Verifies thread-safe connectivity initialization under concurrent calls.
      • Amazon SQS: Ensures visibility timeout clamps to allowed limits.
      • AWS client configuration: Validates and resolves SQS/SNS configurations correctly.
      • SNS: Confirms string-to-ARN helper builds correct ARNs with defaults and custom options.

@coderabbitai
Copy link

coderabbitai bot commented Sep 11, 2025

Walkthrough

Adds new unit tests across NATS, RabbitMQ, and AWS SQS-related components: a NATS heartbeat override test, a RabbitMQ connectivity thread-safety test, SQS visibility timeout clamping test, SQS client config extension tests, and SNS URI string extension tests. No production code changes.

Changes

Cohort / File(s) Summary
NATS Command Queue Options Tests
test/Savvyio.Extensions.NATS.Tests/Commands/NatsCommandQueueOptionsTest.cs
Adds Heartbeat_Can_Be_Overridden_After_Expires test validating default heartbeat from Expires and manual override behavior.
RabbitMQ Connectivity Thread-Safety Tests
test/Savvyio.Extensions.RabbitMQ.Tests/RabbitMqMessageTest.cs
Adds EnsureConnectivityAsync_IsThreadSafe_WhenCalledConcurrently test to assert single connection initialization under concurrent calls using mocks and reflection.
AWS SQS/SNS Extensions Tests
test/Savvyio.Extensions.SimpleQueueService.Tests/AmazonMessageReceiveOptionsTest.cs, test/Savvyio.Extensions.SimpleQueueService.Tests/ClientConfigExtensionsTest.cs, test/Savvyio.Extensions.SimpleQueueService.Tests/EventDriven/StringExtensionsTest.cs
Adds tests for SQS visibility timeout clamping; ClientConfig extensions validation and resolution; string ToSnsUri default and custom ARN construction.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant T as Test
  participant R as RabbitMqMessage
  participant F as IConnectionFactory (mock)
  participant C as IConnection (mock)
  participant CH as IChannel (mock)

  Note over T,R: Concurrent initialization
  T->>R: EnsureConnectivityAsync()
  par Concurrent call
    T->>R: EnsureConnectivityAsync()
  and
    T->>R: EnsureConnectivityAsync()
  end

  alt First initialization path
    R->>F: CreateConnectionAsync()
    F-->>R: C
    R->>C: CreateChannelAsync()
    C-->>R: CH
    R-->>T: Completed
  else Already initialized
    R-->>T: Completed (no new connection)
  end

  Note over F: Verify called exactly once
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Pre-merge checks (2 passed, 1 warning)

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "Expand messaging extension test coverage" succinctly and accurately reflects the primary change — adding unit tests to expand coverage for messaging-related extensions (SQS/SNS, NATS, RabbitMQ and related helpers). It is concise, on-topic, and readable for reviewers scanning history.

Poem

A thump of paws, a twitching nose,
I test the queues where traffic flows.
NATS beats steady, Rabbit hops in sync,
SQS keeps time—no overflow brink.
SNS sings ARNs so neat—
All green lights now, my work complete! 🐇✨

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/improve-test-coverage-for-extensions

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gimlichael gimlichael self-assigned this Sep 11, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
test/Savvyio.Extensions.SimpleQueueService.Tests/AmazonMessageReceiveOptionsTest.cs (1)

49-59: Good clamp coverage; add boundary asserts inline.

Nice edge coverage. Add explicit boundary checks for 0s and exactly Max to prevent regressions.

Apply this diff:

         [Fact]
         public void VisibilityTimeout_ShouldClampValue_WhenOutsideRangeOfAllowedLimits()
         {
             var sut = new AmazonMessageReceiveOptions();

             sut.VisibilityTimeout = TimeSpan.MinValue;
             Assert.Equal(TimeSpan.Zero, sut.VisibilityTimeout);
+            
+            // Lower boundary exact
+            sut.VisibilityTimeout = TimeSpan.Zero;
+            Assert.Equal(TimeSpan.Zero, sut.VisibilityTimeout);

             sut.VisibilityTimeout = TimeSpan.FromSeconds(AmazonMessageOptions.MaxVisibilityTimeoutInSeconds + 1);
             Assert.Equal(TimeSpan.FromSeconds(AmazonMessageOptions.MaxVisibilityTimeoutInSeconds), sut.VisibilityTimeout);
+            
+            // Upper boundary exact
+            sut.VisibilityTimeout = TimeSpan.FromSeconds(AmazonMessageOptions.MaxVisibilityTimeoutInSeconds);
+            Assert.Equal(TimeSpan.FromSeconds(AmazonMessageOptions.MaxVisibilityTimeoutInSeconds), sut.VisibilityTimeout);
         }
test/Savvyio.Extensions.NATS.Tests/Commands/NatsCommandQueueOptionsTest.cs (1)

72-82: Override behavior looks correct; strengthen with persistence check.

After manual override, ensure subsequent Expires updates don’t reset Heartbeat.

Apply this diff:

         public void Heartbeat_Can_Be_Overridden_After_Expires()
         {
             var options = new NatsCommandQueueOptions();

             options.Expires = TimeSpan.FromSeconds(60);
             Assert.Equal(TimeSpan.FromSeconds(5), options.Heartbeat);

             options.Heartbeat = TimeSpan.FromSeconds(15);
             Assert.Equal(TimeSpan.FromSeconds(15), options.Heartbeat);
+            
+            // Verify override persists even if Expires changes again
+            options.Expires = TimeSpan.FromSeconds(45);
+            Assert.Equal(TimeSpan.FromSeconds(15), options.Heartbeat);
         }
test/Savvyio.Extensions.SimpleQueueService.Tests/ClientConfigExtensionsTest.cs (1)

14-25: Solid validity checks.

Covers null, happy path, and wrong length. Consider adding a case with unrelated configs to assert false.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 52b1264 and db6d8eb.

📒 Files selected for processing (5)
  • test/Savvyio.Extensions.NATS.Tests/Commands/NatsCommandQueueOptionsTest.cs (1 hunks)
  • test/Savvyio.Extensions.RabbitMQ.Tests/RabbitMqMessageTest.cs (1 hunks)
  • test/Savvyio.Extensions.SimpleQueueService.Tests/AmazonMessageReceiveOptionsTest.cs (1 hunks)
  • test/Savvyio.Extensions.SimpleQueueService.Tests/ClientConfigExtensionsTest.cs (1 hunks)
  • test/Savvyio.Extensions.SimpleQueueService.Tests/EventDriven/StringExtensionsTest.cs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*Test.cs

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*Test.cs: All unit test classes must inherit from Codebelt.Extensions.Xunit.Test
Use [Fact] for standard unit tests
Use [Theory] with [InlineData] or other data sources for parameterized tests
Test method names should be descriptive and express expected behavior (e.g., ShouldReturnTrue_WhenConditionIsMet)
Use xUnit Assert methods for all assertions (e.g., Assert.Equal, Assert.NotNull, Assert.Contains)
Keep tests focused, isolated, deterministic, and repeatable; avoid external systems except xUnit and Codebelt.Extensions.Xunit
Prefer dummies, fakes, stubs, and spies; use Moq-based mocks only when necessary
Before overriding or mocking, ensure targeted methods are virtual or abstract
Never mock IMarshaller; use a new JsonMarshaller instance instead

Files:

  • test/Savvyio.Extensions.SimpleQueueService.Tests/AmazonMessageReceiveOptionsTest.cs
  • test/Savvyio.Extensions.NATS.Tests/Commands/NatsCommandQueueOptionsTest.cs
  • test/Savvyio.Extensions.SimpleQueueService.Tests/EventDriven/StringExtensionsTest.cs
  • test/Savvyio.Extensions.SimpleQueueService.Tests/ClientConfigExtensionsTest.cs
  • test/Savvyio.Extensions.RabbitMQ.Tests/RabbitMqMessageTest.cs
test/**/*Test.cs

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Test class files must be named with a Test suffix (e.g., CommandDispatcherTest)

Files:

  • test/Savvyio.Extensions.SimpleQueueService.Tests/AmazonMessageReceiveOptionsTest.cs
  • test/Savvyio.Extensions.NATS.Tests/Commands/NatsCommandQueueOptionsTest.cs
  • test/Savvyio.Extensions.SimpleQueueService.Tests/EventDriven/StringExtensionsTest.cs
  • test/Savvyio.Extensions.SimpleQueueService.Tests/ClientConfigExtensionsTest.cs
  • test/Savvyio.Extensions.RabbitMQ.Tests/RabbitMqMessageTest.cs
test/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Place tests in dedicated test projects/folders (under the test directory)

Files:

  • test/Savvyio.Extensions.SimpleQueueService.Tests/AmazonMessageReceiveOptionsTest.cs
  • test/Savvyio.Extensions.NATS.Tests/Commands/NatsCommandQueueOptionsTest.cs
  • test/Savvyio.Extensions.SimpleQueueService.Tests/EventDriven/StringExtensionsTest.cs
  • test/Savvyio.Extensions.SimpleQueueService.Tests/ClientConfigExtensionsTest.cs
  • test/Savvyio.Extensions.RabbitMQ.Tests/RabbitMqMessageTest.cs
test/**/*.cs

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use namespaces in tests that mirror the source code structure

Files:

  • test/Savvyio.Extensions.SimpleQueueService.Tests/AmazonMessageReceiveOptionsTest.cs
  • test/Savvyio.Extensions.NATS.Tests/Commands/NatsCommandQueueOptionsTest.cs
  • test/Savvyio.Extensions.SimpleQueueService.Tests/EventDriven/StringExtensionsTest.cs
  • test/Savvyio.Extensions.SimpleQueueService.Tests/ClientConfigExtensionsTest.cs
  • test/Savvyio.Extensions.RabbitMQ.Tests/RabbitMqMessageTest.cs
test/**/*.Tests/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Unit tests for an assembly should reside in a corresponding .Tests assembly (e.g., Savvyio.Foo.Tests)

Files:

  • test/Savvyio.Extensions.SimpleQueueService.Tests/AmazonMessageReceiveOptionsTest.cs
  • test/Savvyio.Extensions.NATS.Tests/Commands/NatsCommandQueueOptionsTest.cs
  • test/Savvyio.Extensions.SimpleQueueService.Tests/EventDriven/StringExtensionsTest.cs
  • test/Savvyio.Extensions.SimpleQueueService.Tests/ClientConfigExtensionsTest.cs
  • test/Savvyio.Extensions.RabbitMQ.Tests/RabbitMqMessageTest.cs
**/*.cs

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.cs: Follow the repository’s established XML documentation style
Add XML documentation comments to public and protected classes and methods where appropriate

Files:

  • test/Savvyio.Extensions.SimpleQueueService.Tests/AmazonMessageReceiveOptionsTest.cs
  • test/Savvyio.Extensions.NATS.Tests/Commands/NatsCommandQueueOptionsTest.cs
  • test/Savvyio.Extensions.SimpleQueueService.Tests/EventDriven/StringExtensionsTest.cs
  • test/Savvyio.Extensions.SimpleQueueService.Tests/ClientConfigExtensionsTest.cs
  • test/Savvyio.Extensions.RabbitMQ.Tests/RabbitMqMessageTest.cs
🧬 Code graph analysis (1)
test/Savvyio.Extensions.RabbitMQ.Tests/RabbitMqMessageTest.cs (1)
src/Savvyio.Extensions.RabbitMQ/RabbitMqMessage.cs (4)
  • Task (67-84)
  • Task (118-121)
  • RabbitMqMessage (14-122)
  • RabbitMqMessage (36-45)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: call-build (Release) / 🛠️ Build
🔇 Additional comments (3)
test/Savvyio.Extensions.SimpleQueueService.Tests/EventDriven/StringExtensionsTest.cs (2)

20-31: LGTM.

Custom options path is clear and assertions are precise.


12-18: Defaults test verified — implementation defaults match the asserted ARN. ToSnsUri builds arn:{options.Partition}:sns:{options.Region}:{options.AccountId}:{source} (src/Savvyio.Extensions.SimpleQueueService/EventDriven/StringExtensions.cs) and AmazonResourceNameOptions defaults are Partition = RegionEndpoint.EUWest1.PartitionName, Region = RegionEndpoint.EUWest1.SystemName, AccountId = "000000000000" (src/Savvyio.Extensions.SimpleQueueService/AmazonResourceNameOptions.cs).

test/Savvyio.Extensions.SimpleQueueService.Tests/ClientConfigExtensionsTest.cs (1)

27-36: LGTM.

Resolution helpers correctly return the expected instances.

Comment on lines +104 to +129
[Fact]
public async Task EnsureConnectivityAsync_IsThreadSafe_WhenCalledConcurrently()
{
var marshaller = new Mock<IMarshaller>().Object;
var options = new RabbitMqMessageOptions { AmqpUrl = new Uri("amqp://localhost:5672") };

var connectionMock = new Mock<IConnection>();
var channelMock = new Mock<IChannel>();
connectionMock.Setup(c => c.CreateChannelAsync(It.IsAny<CreateChannelOptions?>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(channelMock.Object);

var factoryMock = new Mock<IConnectionFactory>();
factoryMock.Setup(f => f.CreateConnectionAsync(It.IsAny<CancellationToken>()))
.ReturnsAsync(connectionMock.Object);

var sut = new TestRabbitMqMessage(marshaller, options);
typeof(RabbitMqMessage)
.GetProperty("RabbitMqFactory", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
.SetValue(sut, factoryMock.Object);

await Task.WhenAll(
sut.CallEnsureConnectivityAsync(),
sut.CallEnsureConnectivityAsync());

factoryMock.Verify(f => f.CreateConnectionAsync(It.IsAny<CancellationToken>()), Times.Once);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Don’t mock IMarshaller; use a JsonMarshaller. Also verify CreateChannelAsync once.

Repo guideline: “Never mock IMarshaller; use a new JsonMarshaller instance instead.” Replace the mock and add a verify for channel creation.

Apply this diff:

         public async Task EnsureConnectivityAsync_IsThreadSafe_WhenCalledConcurrently()
         {
-            var marshaller = new Mock<IMarshaller>().Object;
+            var marshaller = new JsonMarshaller();
             var options = new RabbitMqMessageOptions { AmqpUrl = new Uri("amqp://localhost:5672") };
@@
             await Task.WhenAll(
                 sut.CallEnsureConnectivityAsync(),
                 sut.CallEnsureConnectivityAsync());
 
             factoryMock.Verify(f => f.CreateConnectionAsync(It.IsAny<CancellationToken>()), Times.Once);
+            connectionMock.Verify(c => c.CreateChannelAsync(It.IsAny<CreateChannelOptions?>(), It.IsAny<CancellationToken>()), Times.Once);
         }

Add the appropriate using for JsonMarshaller (adjust namespace to your concrete type if different):

using Savvyio.Serialization; // or the namespace where JsonMarshaller resides
🤖 Prompt for AI Agents
In test/Savvyio.Extensions.RabbitMQ.Tests/RabbitMqMessageTest.cs around lines
104 to 129, replace the mocked IMarshaller with a real JsonMarshaller instance
(add the appropriate using for its namespace), and after the concurrent
EnsureConnectivity calls add a Verify on the connectionMock.CreateChannelAsync
(or channelMock depending on method) to assert it was invoked once;
specifically: construct new JsonMarshaller() instead of
Mock<IMarshaller>().Object, add the using for Savvyio.Serialization (or the
correct namespace), and add factoryMock.Verify for
CreateConnectionAsync(Times.Once) is already present and add
channelMock.Verify(c => c.CreateChannelAsync(It.IsAny<CreateChannelOptions?>(),
It.IsAny<CancellationToken>()), Times.Once) to confirm single channel creation.

@codecov
Copy link

codecov bot commented Sep 11, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 78.01%. Comparing base (52b1264) to head (db6d8eb).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #41      +/-   ##
==========================================
+ Coverage   77.82%   78.01%   +0.18%     
==========================================
  Files         177      177              
  Lines        3711     3711              
  Branches      365      365              
==========================================
+ Hits         2888     2895       +7     
+ Misses        821      815       -6     
+ Partials        2        1       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@sonarqubecloud
Copy link

@gimlichael gimlichael merged commit 5863232 into main Sep 14, 2025
142 checks passed
@gimlichael gimlichael deleted the codex/improve-test-coverage-for-extensions branch September 14, 2025 16:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants