< Summary - AsyncResponse (Release / net8.0+net10.0 / unit+integration)

Information
Class: AsyncResponse.Transports.Kafka.KafkaReplyTargetProvider
Assembly: AsyncResponse.Transports.Kafka
File(s): /_/src/Transports/AsyncResponse.Transports.Kafka/KafkaReplyTargetProvider.cs
Line coverage
100%
Covered lines: 47
Uncovered lines: 0
Coverable lines: 47
Total lines: 79
Line coverage: 100%
Branch coverage
93%
Covered branches: 15
Total branches: 16
Branch coverage: 93.7%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
GetReplyTarget(...)91.66%1212100%
ResolveTarget(...)100%44100%

File(s)

/_/src/Transports/AsyncResponse.Transports.Kafka/KafkaReplyTargetProvider.cs

#LineLine coverage
 1using Microsoft.Extensions.Options;
 2
 3namespace AsyncResponse.Transports.Kafka;
 4
 2075internal sealed class KafkaReplyTargetProvider(
 2076    IOptions<KafkaAsyncResponseTransportOptions> _options) : IAsyncResponseReplyTargetProvider
 7{
 8    /// <summary>Gets the configured reply target.</summary>
 9    public AsyncResponseReplyTarget GetReplyTarget(string? name = null)
 10    {
 1211        var options = _options.Value;
 1212        KafkaTransportOptionsValidator.ValidateCommon(options);
 1213        var schema = new KafkaTransportTopicSchema(options);
 1214        var targetName = string.IsNullOrWhiteSpace(name)
 1215            ? options.DefaultReplyTargetName
 1216            : name;
 17
 1218        var target = ResolveTarget(options, schema, targetName);
 1019        var responseTopic = KafkaTransportOptionsValidator.Required(
 1020            target.ResponseTopic,
 1021            $"{nameof(KafkaReplyTargetOptions)}.{nameof(KafkaReplyTargetOptions.ResponseTopic)}");
 1022        var consumerGroup = target.ConsumerGroup ?? options.ResponseConsumerGroup;
 23
 24        // ValidateCommon enforces distinctness for the transport-wide topics; a NAMED target must
 25        // honor the same rule (DB-transport parity) — aimed at the worker topic its responses are
 26        // consumed as worker jobs, and aimed at a derived dead-letter topic they are mixed into
 27        // buried traffic, while the waiter times out.
 1028        if (StringComparer.Ordinal.Equals(responseTopic, schema.WorkerTopic)
 1029            || StringComparer.Ordinal.Equals(responseTopic, schema.DeadLetterTopicFor(schema.WorkerTopic))
 1030            || StringComparer.Ordinal.Equals(responseTopic, schema.DeadLetterTopicFor(schema.ResponseTopic)))
 31        {
 632            throw new InvalidOperationException(
 633                $"Kafka async-response reply target '{targetName}' uses topic '{responseTopic}', which collides with " +
 634                $"{nameof(KafkaAsyncResponseTransportOptions.WorkerTopic)} or a derived dead-letter topic; " +
 635                "its responses would be consumed as worker jobs (or mixed into dead letters).");
 36        }
 37
 438        var properties = new Dictionary<string, string>(target.Properties, StringComparer.Ordinal)
 439        {
 440            ["topic"] = responseTopic,
 441            ["consumerGroup"] = consumerGroup,
 442            ["correlationIdHeader"] = options.CorrelationIdHeader
 443        };
 44
 445        if (!string.IsNullOrWhiteSpace(options.BootstrapServers))
 446            properties["bootstrapServers"] = options.BootstrapServers!;
 47
 448        return new AsyncResponseReplyTarget
 449        {
 450            Name = targetName,
 451            Transport = KafkaAsyncResponseTransportOptions.TransportName,
 452            Address = responseTopic,
 453            Properties = properties
 454        };
 55    }
 56
 57    private static KafkaReplyTargetOptions ResolveTarget(
 58        KafkaAsyncResponseTransportOptions options,
 59        KafkaTransportTopicSchema schema,
 60        string targetName)
 61    {
 1262        if (options.ReplyTargets.TryGetValue(targetName, out var configured))
 863            return configured;
 64
 465        if (StringComparer.Ordinal.Equals(targetName, options.DefaultReplyTargetName))
 66        {
 267            return new KafkaReplyTargetOptions
 268            {
 269                ResponseTopic = schema.ResponseTopic,
 270                ConsumerGroup = options.ResponseConsumerGroup
 271            };
 72        }
 73
 274        throw new InvalidOperationException(
 275            $"Kafka async-response reply target '{targetName}' is not configured. " +
 276            $"Configure {nameof(KafkaAsyncResponseTransportOptions.ResponseTopic)} for the default target " +
 277            $"or add a named target with {nameof(KafkaAsyncResponseTransportOptions.AddReplyTarget)}.");
 78    }
 79}