diff --git a/src/JustEat.StatsD/Buffered/StatsDUtf8Formatter.cs b/src/JustEat.StatsD/Buffered/StatsDUtf8Formatter.cs index 66e48729..eee6a99d 100644 --- a/src/JustEat.StatsD/Buffered/StatsDUtf8Formatter.cs +++ b/src/JustEat.StatsD/Buffered/StatsDUtf8Formatter.cs @@ -4,7 +4,7 @@ namespace JustEat.StatsD.Buffered { - internal class StatsDUtf8Formatter + internal sealed class StatsDUtf8Formatter { private readonly byte[] _utf8Prefix; diff --git a/src/JustEat.StatsD/DisposableTimer.cs b/src/JustEat.StatsD/DisposableTimer.cs index b90040bc..0931bcb4 100644 --- a/src/JustEat.StatsD/DisposableTimer.cs +++ b/src/JustEat.StatsD/DisposableTimer.cs @@ -10,18 +10,18 @@ internal sealed class DisposableTimer : IDisposableTimer private IStatsDPublisher _publisher; private Stopwatch _stopwatch; - public string StatName { get; set; } + public string Bucket { get; set; } - public DisposableTimer(IStatsDPublisher publisher, string statName) + public DisposableTimer(IStatsDPublisher publisher, string bucket) { _publisher = publisher ?? throw new ArgumentNullException(nameof(publisher)); - if (string.IsNullOrEmpty(statName)) + if (string.IsNullOrEmpty(bucket)) { - throw new ArgumentNullException(nameof(statName)); + throw new ArgumentNullException(nameof(bucket)); } - StatName = statName; + Bucket = bucket; _stopwatch = Stopwatch.StartNew(); } @@ -32,12 +32,12 @@ public void Dispose() _disposed = true; _stopwatch.Stop(); - if (string.IsNullOrEmpty(StatName)) + if (string.IsNullOrEmpty(Bucket)) { - throw new InvalidOperationException($"The {nameof(StatName)} property must have a value."); + throw new InvalidOperationException($"The {nameof(Bucket)} property must have a value."); } - _publisher.Timing(_stopwatch.Elapsed, StatName); + _publisher.Timing(_stopwatch.Elapsed, Bucket); _stopwatch = null; _publisher = null; diff --git a/src/JustEat.StatsD/EndpointLookups/CachedEndpointSource.cs b/src/JustEat.StatsD/EndpointLookups/CachedEndpointSource.cs index a9d60386..8b8d59b1 100644 --- a/src/JustEat.StatsD/EndpointLookups/CachedEndpointSource.cs +++ b/src/JustEat.StatsD/EndpointLookups/CachedEndpointSource.cs @@ -22,9 +22,18 @@ public class CachedEndpointSource : IEndPointSource /// /// is . /// + /// + /// is less than or equal to . + /// public CachedEndpointSource(IEndPointSource inner, TimeSpan cacheDuration) { _inner = inner ?? throw new ArgumentNullException(nameof(inner)); + + if (cacheDuration <= TimeSpan.Zero) + { + throw new ArgumentOutOfRangeException(nameof(cacheDuration), cacheDuration, "The end point cache duration must be a positive TimeSpan value."); + } + _cachedValue = null; _cacheDuration = cacheDuration; } diff --git a/src/JustEat.StatsD/EndpointLookups/DnsLookupIpEndpointSource.cs b/src/JustEat.StatsD/EndpointLookups/DnsLookupIpEndpointSource.cs index b6e6053d..a820844e 100644 --- a/src/JustEat.StatsD/EndpointLookups/DnsLookupIpEndpointSource.cs +++ b/src/JustEat.StatsD/EndpointLookups/DnsLookupIpEndpointSource.cs @@ -7,7 +7,7 @@ namespace JustEat.StatsD.EndpointLookups { /// /// A class representing an implementation of that looks up - /// the for DNS hostname to resolve its IP address. + /// the for a DNS hostname to resolve its IP address. /// public class DnsLookupIpEndpointSource : IEndPointSource { diff --git a/src/JustEat.StatsD/IDisposableTimer.cs b/src/JustEat.StatsD/IDisposableTimer.cs index 325ce90f..9f60575e 100644 --- a/src/JustEat.StatsD/IDisposableTimer.cs +++ b/src/JustEat.StatsD/IDisposableTimer.cs @@ -8,8 +8,8 @@ namespace JustEat.StatsD public interface IDisposableTimer : IDisposable { /// - /// Gets or sets the name of the StatsD bucket associated with the timer. + /// Gets or sets the StatsD bucket associated with the timer. /// - string StatName { get; set; } + string Bucket { get; set; } } } diff --git a/src/JustEat.StatsD/SocketProtocol.cs b/src/JustEat.StatsD/SocketProtocol.cs index e0327336..8694d958 100644 --- a/src/JustEat.StatsD/SocketProtocol.cs +++ b/src/JustEat.StatsD/SocketProtocol.cs @@ -1,9 +1,11 @@ +using System.Net.Sockets; + namespace JustEat.StatsD { /// - /// The subset of ProtocolType that are supported by SocketTransport - /// UDP or IP. - /// UDP is the default, but IP transport is required for AWS Lambdas. + /// An enumeration defining the subset of values that are supported by . + /// + /// UDP is the default, but IP transport is required for some environments such as AWS Lambda functions. /// public enum SocketProtocol { diff --git a/src/JustEat.StatsD/TimerExtensions.cs b/src/JustEat.StatsD/TimerExtensions.cs index ddab4d90..06315e07 100644 --- a/src/JustEat.StatsD/TimerExtensions.cs +++ b/src/JustEat.StatsD/TimerExtensions.cs @@ -18,6 +18,9 @@ public static class TimerExtensions /// /// An that publishes the metric when the instance is disposed of. /// + /// + /// or is . + /// public static IDisposableTimer StartTimer(this IStatsDPublisher publisher, string bucket) { return new DisposableTimer(publisher, bucket); @@ -30,8 +33,16 @@ public static IDisposableTimer StartTimer(this IStatsDPublisher publisher, strin /// The to publish with. /// The bucket to publish the timer for. /// A delegate to a method whose invocation should be timed. + /// + /// , or is . + /// public static void Time(this IStatsDPublisher publisher, string bucket, Action action) { + if (action == null) + { + throw new ArgumentNullException(nameof(action)); + } + using (StartTimer(publisher, bucket)) { action(); @@ -45,8 +56,16 @@ public static void Time(this IStatsDPublisher publisher, string bucket, Action a /// The to publish with. /// The bucket to publish the timer for. /// A delegate to a method whose invocation should be timed. + /// + /// , or is . + /// public static void Time(this IStatsDPublisher publisher, string bucket, Action action) { + if (action == null) + { + throw new ArgumentNullException(nameof(action)); + } + using (var timer = StartTimer(publisher, bucket)) { action(timer); @@ -63,8 +82,16 @@ public static void Time(this IStatsDPublisher publisher, string bucket, Action /// A representing the asynchronous operation to time. /// + /// + /// , or is . + /// public static async Task Time(this IStatsDPublisher publisher, string bucket, Func action) { + if (action == null) + { + throw new ArgumentNullException(nameof(action)); + } + using (StartTimer(publisher, bucket)) { await action().ConfigureAwait(false); @@ -82,8 +109,16 @@ public static async Task Time(this IStatsDPublisher publisher, string bucket, Fu /// /// A representing the asynchronous operation to time. /// + /// + /// , or is . + /// public static async Task Time(this IStatsDPublisher publisher, string bucket, Func action) { + if (action == null) + { + throw new ArgumentNullException(nameof(action)); + } + using (var timer = StartTimer(publisher, bucket)) { await action(timer).ConfigureAwait(false); @@ -101,8 +136,16 @@ public static async Task Time(this IStatsDPublisher publisher, string bucket, Fu /// /// The value from invoking . /// + /// + /// , or is . + /// public static T Time(this IStatsDPublisher publisher, string bucket, Func func) { + if (func == null) + { + throw new ArgumentNullException(nameof(func)); + } + using (StartTimer(publisher, bucket)) { return func(); @@ -120,8 +163,16 @@ public static T Time(this IStatsDPublisher publisher, string bucket, Func /// /// The value from invoking . /// + /// + /// , or is . + /// public static T Time(this IStatsDPublisher publisher, string bucket, Func func) { + if (func == null) + { + throw new ArgumentNullException(nameof(func)); + } + using (var timer = StartTimer(publisher, bucket)) { return func(timer); @@ -139,8 +190,16 @@ public static T Time(this IStatsDPublisher publisher, string bucket, Func /// A representing the asynchronous operation to time. /// + /// + /// , or is . + /// public static async Task Time(this IStatsDPublisher publisher, string bucket, Func> func) { + if (func == null) + { + throw new ArgumentNullException(nameof(func)); + } + using (StartTimer(publisher, bucket)) { return await func().ConfigureAwait(false); @@ -158,8 +217,16 @@ public static async Task Time(this IStatsDPublisher publisher, string buck /// /// A representing the asynchronous operation to time. /// + /// + /// , or is . + /// public static async Task Time(this IStatsDPublisher publisher, string bucket, Func> func) { + if (func == null) + { + throw new ArgumentNullException(nameof(func)); + } + using (var timer = StartTimer(publisher, bucket)) { return await func(timer).ConfigureAwait(false); diff --git a/tests/JustEat.StatsD.Tests/EndpointLookups/CachedEndpointSourceTests.cs b/tests/JustEat.StatsD.Tests/EndpointLookups/CachedEndpointSourceTests.cs index b8cbe94d..c94529fa 100644 --- a/tests/JustEat.StatsD.Tests/EndpointLookups/CachedEndpointSourceTests.cs +++ b/tests/JustEat.StatsD.Tests/EndpointLookups/CachedEndpointSourceTests.cs @@ -62,6 +62,21 @@ public static async Task CachedValueIsReturnedAgainAfterExpiry() mockInner.Verify(x => x.GetEndpoint(), Times.Exactly(2)); } + [Theory] + [InlineData(0)] + [InlineData(-1)] + public static void ConstructorThrowsIfCacheDurationIsInvalid(long ticks) + { + // Arrange + var inner = Mock.Of(); + var cacheDuration = TimeSpan.FromTicks(ticks); + + // Act and Assert + var exception = Assert.Throws("cacheDuration", () => new CachedEndpointSource(inner, cacheDuration)); + + exception.ActualValue.ShouldBe(cacheDuration); + } + private static IPEndPoint MakeTestIpEndPoint() { return new IPEndPoint(new IPAddress(new byte[] { 1, 2, 3, 4 }), 8125); diff --git a/tests/JustEat.StatsD.Tests/Extensions/ExtensionsTests.cs b/tests/JustEat.StatsD.Tests/Extensions/ExtensionsTests.cs index b052fbdf..230734ed 100644 --- a/tests/JustEat.StatsD.Tests/Extensions/ExtensionsTests.cs +++ b/tests/JustEat.StatsD.Tests/Extensions/ExtensionsTests.cs @@ -29,7 +29,7 @@ public static void CanChangeStatName() using (var timer = publisher.StartTimer("defaultName")) { Delay(); - timer.StatName = "otherStat"; + timer.Bucket = "otherStat"; } PublisherAssertions.SingleStatNameIs(publisher, "otherStat"); @@ -120,7 +120,7 @@ public static void CanChangeStatNameInAction() publisher.Time("defaultName", t => { Delay(); - t.StatName = "otherStat"; + t.Bucket = "otherStat"; }); PublisherAssertions.SingleStatNameIs(publisher, "otherStat"); @@ -182,7 +182,7 @@ public static async Task CanChangeStatNameInAsyncFunction() await publisher.Time("defaultName", async t => { var result = await DelayedAnswerAsync(); - t.StatName = "afterTheAwait"; + t.Bucket = "afterTheAwait"; return result; }); diff --git a/tests/JustEat.StatsD.Tests/Extensions/SimpleTimerStatNameTests.cs b/tests/JustEat.StatsD.Tests/Extensions/SimpleTimerStatNameTests.cs index b771c06a..22c60266 100644 --- a/tests/JustEat.StatsD.Tests/Extensions/SimpleTimerStatNameTests.cs +++ b/tests/JustEat.StatsD.Tests/Extensions/SimpleTimerStatNameTests.cs @@ -28,7 +28,7 @@ public static void CanChangeStatNameDuringOperation() using (var timer = publisher.StartTimer("initialStat")) { Delay(); - timer.StatName = "changedValue"; + timer.Bucket = "changedValue"; } PublisherAssertions.SingleStatNameIs(publisher, "changedValue"); @@ -42,7 +42,7 @@ public static void StatNameCanBeAppended() using (var timer = publisher.StartTimer("Some.")) { Delay(); - timer.StatName += "More"; + timer.Bucket += "More"; } PublisherAssertions.SingleStatNameIs(publisher, "Some.More"); @@ -69,7 +69,7 @@ public static void StatWithoutNameAtEndThrows() using (var timer = publisher.StartTimer("valid.Stat")) { Delay(); - timer.StatName = null; + timer.Bucket = null; } }); @@ -88,7 +88,7 @@ public static void StatNameIsInitialValueWhenExceptionIsThrown() using (var timer = publisher.StartTimer("initialStat")) { Fail(); - timer.StatName = "changedValue"; + timer.Bucket = "changedValue"; } } catch (Exception)