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

Information
Class: AsyncResponse.Transports.NATS.NatsTransportOptionsValidator
Assembly: AsyncResponse.Transports.NATS
File(s): /home/runner/work/AsyncResponse/AsyncResponse/src/Transports/AsyncResponse.Transports.NATS/NatsTransportOptionsValidator.cs
Line coverage
100%
Covered lines: 59
Uncovered lines: 0
Coverable lines: 59
Total lines: 111
Line coverage: 100%
Branch coverage
100%
Covered branches: 30
Total branches: 30
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
Required(...)100%22100%
Positive(...)100%22100%
PositiveOrNull(...)100%44100%
ValidateCommon(...)100%88100%
ValidateSubscriber(...)100%22100%
ValidateSubscriber(...)100%1212100%

File(s)

/home/runner/work/AsyncResponse/AsyncResponse/src/Transports/AsyncResponse.Transports.NATS/NatsTransportOptionsValidator.cs

#LineLine coverage
 1namespace AsyncResponse.Transports.NATS;
 2
 3internal static class NatsTransportOptionsValidator
 4{
 5    /// <summary>Validates the supplied options.</summary>
 6    public static string Required(string? value, string name)
 37        => !string.IsNullOrWhiteSpace(value)
 38            ? value
 39            : throw new InvalidOperationException($"{nameof(NatsAsyncResponseTransportOptions)}.{name} must be configure
 10
 11    /// <summary>Validates the supplied options.</summary>
 12    public static void Positive(TimeSpan value, string name)
 13    {
 314        if (value <= TimeSpan.Zero)
 315            throw new InvalidOperationException($"{nameof(NatsAsyncResponseTransportOptions)}.{name} must be positive.")
 316    }
 17
 18    /// <summary>Validates the supplied options.</summary>
 19    public static void PositiveOrNull(long? value, string name)
 20    {
 321        if (value is <= 0)
 322            throw new InvalidOperationException($"{nameof(NatsAsyncResponseTransportOptions)}.{name} must be positive wh
 323    }
 24
 25    /// <summary>Validates the supplied options.</summary>
 26    public static void ValidateCommon(NatsAsyncResponseTransportOptions options)
 27    {
 328        _ = Required(options.SubjectPrefix, nameof(options.SubjectPrefix));
 329        _ = Required(options.WorkerConsumer, nameof(options.WorkerConsumer));
 330        _ = Required(options.ResponseConsumer, nameof(options.ResponseConsumer));
 331        _ = Required(options.CorrelationIdHeader, nameof(options.CorrelationIdHeader));
 332        _ = Required(options.DefaultReplyTargetName, nameof(options.DefaultReplyTargetName));
 33
 34        // A subject prefix becomes leading tokens of every transport subject; it must not contain
 35        // whitespace or the NATS subject wildcards.
 336        if (options.SubjectPrefix.IndexOfAny([' ', '\t', '*', '>', '\r', '\n']) >= 0)
 337            throw new InvalidOperationException(
 338                $"{nameof(NatsAsyncResponseTransportOptions)}.{nameof(options.SubjectPrefix)} '{options.SubjectPrefix}' 
 39
 340        Positive(options.AckWait, nameof(options.AckWait));
 341        Positive(options.PublishRetryBaseDelay, nameof(options.PublishRetryBaseDelay));
 342        Positive(options.PublishRetryMaxDelay, nameof(options.PublishRetryMaxDelay));
 343        Positive(options.SubscriberRetryBaseDelay, nameof(options.SubscriberRetryBaseDelay));
 344        Positive(options.SubscriberRetryMaxDelay, nameof(options.SubscriberRetryMaxDelay));
 345        PositiveOrNull(options.StreamMaxMessages, nameof(options.StreamMaxMessages));
 346        PositiveOrNull(options.DeadLetterStreamMaxMessages, nameof(options.DeadLetterStreamMaxMessages));
 47
 348        if (options.PublishMaxAttempts <= 0)
 349            throw new InvalidOperationException($"{nameof(NatsAsyncResponseTransportOptions)}.{nameof(options.PublishMax
 50
 351        if (options.PublishRetryBaseDelay > options.PublishRetryMaxDelay)
 352            throw new InvalidOperationException(
 353                $"{nameof(NatsAsyncResponseTransportOptions)}.{nameof(options.PublishRetryBaseDelay)} cannot exceed " +
 354                $"{nameof(NatsAsyncResponseTransportOptions)}.{nameof(options.PublishRetryMaxDelay)}.");
 55
 356        if (options.SubscriberRetryBaseDelay > options.SubscriberRetryMaxDelay)
 357            throw new InvalidOperationException(
 358                $"{nameof(NatsAsyncResponseTransportOptions)}.{nameof(options.SubscriberRetryBaseDelay)} cannot exceed "
 359                $"{nameof(NatsAsyncResponseTransportOptions)}.{nameof(options.SubscriberRetryMaxDelay)}.");
 360    }
 61
 62    /// <summary>Validates the supplied subscriber options together with the transport-wide shutdown budget.</summary>
 63    public static void ValidateSubscriber(
 64        NatsAsyncResponseTransportOptions transportOptions,
 65        NatsSubscriberOptions subscriber,
 66        string role)
 67    {
 368        ValidateSubscriber(subscriber, role);
 69
 370        if (subscriber.AckMode is not NatsAckMode.AckAfterEnqueue)
 371            return;
 72
 73        // NATS subscribers spend only the background drain at shutdown; the consume loop stops
 74        // with the host token and the connection teardown is not separately bounded.
 375        ShutdownBudgetValidator.Validate(
 376            "NATS",
 377            $"{nameof(NatsAsyncResponseTransportOptions)}.{nameof(transportOptions.HostShutdownTimeout)}",
 378            transportOptions.HostShutdownTimeout,
 379            ($"{nameof(NatsSubscriberOptions)}.{nameof(subscriber.BackgroundDrainTimeout)} ({role})", subscriber.Backgro
 380    }
 81
 82    /// <summary>Validates the supplied options.</summary>
 83    public static void ValidateSubscriber(NatsSubscriberOptions subscriber, string role)
 84    {
 385        if (subscriber.BatchSize <= 0)
 386            throw new InvalidOperationException($"{nameof(NatsSubscriberOptions)}.{nameof(subscriber.BatchSize)} ({role}
 87
 388        if (subscriber.MaxDeliveryAttempts < 0)
 389            throw new InvalidOperationException($"{nameof(NatsSubscriberOptions)}.{nameof(subscriber.MaxDeliveryAttempts
 90
 391        Positive(subscriber.RedeliveryDelay, $"{nameof(subscriber.RedeliveryDelay)} ({role})");
 92
 393        switch (subscriber.AckMode)
 94        {
 95            case NatsAckMode.AckAfterHandlerCompletes:
 396                return;
 97
 98            case NatsAckMode.AckAfterEnqueue:
 399                if (subscriber.BackgroundWorkerCount <= 0)
 3100                    throw new InvalidOperationException($"{nameof(NatsSubscriberOptions)}.{nameof(subscriber.BackgroundW
 3101                if (subscriber.BackgroundQueueCapacity <= 0)
 3102                    throw new InvalidOperationException($"{nameof(NatsSubscriberOptions)}.{nameof(subscriber.BackgroundQ
 3103                Positive(subscriber.BackgroundDrainTimeout, $"{nameof(subscriber.BackgroundDrainTimeout)} ({role})");
 3104                return;
 105
 106            default:
 3107                throw new InvalidOperationException(
 3108                    $"{nameof(NatsSubscriberOptions)}.{nameof(subscriber.AckMode)} ({role}) has unsupported value '{subs
 109        }
 110    }
 111}