Skip to content

Commit

Permalink
Adopt FakeTimeProvider
Browse files Browse the repository at this point in the history
Use a source copy of `FakeTimeProvider` for tests that do not depend on cancellation behaviours or verify the implementation's internal calls.
  • Loading branch information
martincostello committed Jun 24, 2023
1 parent 9fb7dab commit 195c40a
Show file tree
Hide file tree
Showing 12 changed files with 341 additions and 54 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
using Microsoft.Extensions.Time.Testing;
using Polly.CircuitBreaker;

namespace Polly.Core.Tests.CircuitBreaker;
Expand Down Expand Up @@ -100,10 +101,8 @@ public void AddCircuitBreaker_IntegrationTest()
OnHalfOpened = (_) => { halfOpened++; return default; }
};

var timeProvider = new MockTimeProvider();
var strategy = new ResilienceStrategyBuilder { TimeProvider = timeProvider.Object }.AddSimpleCircuitBreaker(options).Build();
var time = DateTime.UtcNow;
timeProvider.Setup(v => v.GetUtcNow()).Returns(() => time);
var timeProvider = new FakeTimeProvider();
var strategy = new ResilienceStrategyBuilder { TimeProvider = timeProvider }.AddSimpleCircuitBreaker(options).Build();

for (int i = 0; i < options.FailureThreshold; i++)
{
Expand All @@ -117,15 +116,15 @@ public void AddCircuitBreaker_IntegrationTest()
Assert.Throws<BrokenCircuitException<object>>(() => strategy.Execute(_ => 0));

// Circuit Half Opened
time += options.BreakDuration;
timeProvider.Advance(options.BreakDuration);
strategy.Execute(_ => -1);
Assert.Throws<BrokenCircuitException<object>>(() => strategy.Execute(_ => 0));
opened.Should().Be(2);
halfOpened.Should().Be(1);
closed.Should().Be(0);

// Now close it
time += options.BreakDuration;
timeProvider.Advance(options.BreakDuration);
strategy.Execute(_ => 0);
opened.Should().Be(2);
halfOpened.Should().Be(2);
Expand All @@ -151,10 +150,8 @@ public void AddAdvancedCircuitBreaker_IntegrationTest()
OnHalfOpened = (_) => { halfOpened++; return default; }
};

var timeProvider = new MockTimeProvider();
var strategy = new ResilienceStrategyBuilder { TimeProvider = timeProvider.Object }.AddAdvancedCircuitBreaker(options).Build();
var time = DateTime.UtcNow;
timeProvider.Setup(v => v.GetUtcNow()).Returns(() => time);
var timeProvider = new FakeTimeProvider();
var strategy = new ResilienceStrategyBuilder { TimeProvider = timeProvider }.AddAdvancedCircuitBreaker(options).Build();

for (int i = 0; i < 10; i++)
{
Expand All @@ -168,15 +165,15 @@ public void AddAdvancedCircuitBreaker_IntegrationTest()
Assert.Throws<BrokenCircuitException<object>>(() => strategy.Execute(_ => 0));

// Circuit Half Opened
time += options.BreakDuration;
timeProvider.Advance(options.BreakDuration);
strategy.Execute(_ => -1);
Assert.Throws<BrokenCircuitException<object>>(() => strategy.Execute(_ => 0));
opened.Should().Be(2);
halfOpened.Should().Be(1);
closed.Should().Be(0);

// Now close it
time += options.BreakDuration;
timeProvider.Advance(options.BreakDuration);
strategy.Execute(_ => 0);
opened.Should().Be(2);
halfOpened.Should().Be(2);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Microsoft.Extensions.Time.Testing;
using Moq;
using Polly.CircuitBreaker;
using Polly.Telemetry;
Expand All @@ -6,16 +7,15 @@ namespace Polly.Core.Tests.CircuitBreaker;

public class CircuitBreakerResilienceStrategyTests : IDisposable
{
private readonly MockTimeProvider _timeProvider;
private readonly FakeTimeProvider _timeProvider;
private readonly Mock<CircuitBehavior> _behavior;
private readonly ResilienceStrategyTelemetry _telemetry;
private readonly SimpleCircuitBreakerStrategyOptions<int> _options;
private readonly CircuitStateController<int> _controller;

public CircuitBreakerResilienceStrategyTests()
{
_timeProvider = new MockTimeProvider();
_timeProvider.Setup(v => v.GetUtcNow()).Returns(DateTime.UtcNow);
_timeProvider = new FakeTimeProvider();
_behavior = new Mock<CircuitBehavior>(MockBehavior.Strict);
_telemetry = TestUtilities.CreateResilienceTelemetry(Mock.Of<DiagnosticSource>());
_options = new SimpleCircuitBreakerStrategyOptions<int>();
Expand All @@ -25,7 +25,7 @@ public CircuitBreakerResilienceStrategyTests()
null,
null,
_behavior.Object,
_timeProvider.Object,
_timeProvider,
_telemetry);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
using Microsoft.Extensions.Time.Testing;
using Moq;
using Polly.CircuitBreaker;
using Polly.Telemetry;

namespace Polly.Core.Tests.CircuitBreaker.Controller;

public class CircuitStateControllerTests
{
private readonly MockTimeProvider _timeProvider = new();
private readonly FakeTimeProvider _timeProvider = new();

private readonly CircuitBreakerStrategyOptions<int> _options = new SimpleCircuitBreakerStrategyOptions<int>();
private readonly Mock<CircuitBehavior> _circuitBehavior = new(MockBehavior.Strict);
private readonly Action<TelemetryEventArguments> _onTelemetry = _ => { };
private DateTimeOffset _utcNow = DateTimeOffset.UtcNow;

public CircuitStateControllerTests() => _timeProvider.Setup(v => v.GetUtcNow()).Returns(() => _utcNow);

[Fact]
public void Ctor_EnsureDefaults()
Expand Down Expand Up @@ -41,7 +41,7 @@ public async Task IsolateAsync_Ok()
return default;
};

_timeProvider.Setup(v => v.GetUtcNow()).Returns(DateTime.UtcNow);
_timeProvider.Advance(TimeSpan.FromSeconds(1));
using var controller = CreateController();
var context = ResilienceContext.Get();

Expand Down Expand Up @@ -79,7 +79,7 @@ public async Task BreakAsync_Ok()
return default;
};

_timeProvider.Setup(v => v.GetUtcNow()).Returns(DateTime.UtcNow);
_timeProvider.Advance(TimeSpan.FromSeconds(1));
using var controller = CreateController();
await controller.IsolateCircuitAsync(ResilienceContext.Get());
_circuitBehavior.Setup(v => v.OnCircuitClosed());
Expand Down Expand Up @@ -123,7 +123,7 @@ public async Task OnActionPreExecute_CircuitOpenedByValue()
error.Should().BeOfType<BrokenCircuitException<int>>();
error.Result.Should().Be(99);

GetBlockedTill(controller).Should().Be(_utcNow + _options.BreakDuration);
GetBlockedTill(controller).Should().Be(_timeProvider.GetUtcNow() + _options.BreakDuration);
}

[Fact]
Expand All @@ -132,7 +132,7 @@ public async Task HalfOpen_EnsureBreakDuration()
using var controller = CreateController();

await TransitionToState(controller, CircuitState.HalfOpen);
GetBlockedTill(controller).Should().Be(_utcNow + _options.BreakDuration);
GetBlockedTill(controller).Should().Be(_timeProvider.GetUtcNow() + _options.BreakDuration);
}

[InlineData(true)]
Expand Down Expand Up @@ -316,12 +316,14 @@ public async Task OnActionFailureAsync_EnsureBreakDurationNotOverflow(bool overf
using var controller = CreateController();
var shouldBreak = true;
await TransitionToState(controller, CircuitState.HalfOpen);
_utcNow = DateTime.MaxValue - _options.BreakDuration;
var utcNow = DateTime.MaxValue - _options.BreakDuration;
if (overflow)
{
_utcNow += TimeSpan.FromMilliseconds(10);
utcNow += TimeSpan.FromMilliseconds(10);
}

_timeProvider.SetUtcNow(utcNow);

_circuitBehavior.Setup(v => v.OnActionFailure(CircuitState.HalfOpen, out shouldBreak));

// act
Expand All @@ -336,7 +338,7 @@ public async Task OnActionFailureAsync_EnsureBreakDurationNotOverflow(bool overf
}
else
{
blockedTill.Should().Be(_utcNow + _options.BreakDuration);
blockedTill.Should().Be(utcNow + _options.BreakDuration);
}
}

Expand Down Expand Up @@ -433,14 +435,14 @@ private async Task OpenCircuit(CircuitStateController<int> controller, Outcome<i
await controller.OnActionFailureAsync(outcome ?? Outcome.FromResult(10), ResilienceContext.Get().Initialize<int>(true));
}

private void AdvanceTime(TimeSpan timespan) => _utcNow += timespan;
private void AdvanceTime(TimeSpan timespan) => _timeProvider.Advance(timespan);

private CircuitStateController<int> CreateController() => new(
_options.BreakDuration,
_options.OnOpened,
_options.OnClosed,
_options.OnHalfOpened,
_circuitBehavior.Object,
_timeProvider.Object,
TestUtilities.CreateResilienceTelemetry(args => _onTelemetry.Invoke(args)));
_timeProvider,
TestUtilities.CreateResilienceTelemetry(_onTelemetry.Invoke));
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
using Microsoft.Extensions.Time.Testing;
using Polly.CircuitBreaker.Health;

namespace Polly.Core.Tests.CircuitBreaker.Health;

public class RollingHealthMetricsTests
{
private readonly MockTimeProvider _timeProvider;
private readonly FakeTimeProvider _timeProvider;
private readonly TimeSpan _samplingDuration = TimeSpan.FromSeconds(10);
private readonly short _windows = 10;

public RollingHealthMetricsTests() => _timeProvider = new MockTimeProvider().SetupUtcNow();
public RollingHealthMetricsTests() => _timeProvider = new FakeTimeProvider();

[Fact]
public void Ctor_EnsureDefaults()
Expand Down Expand Up @@ -53,11 +55,11 @@ public void GetHealthInfo_EnsureWindowRespected()
}

metrics.IncrementSuccess();
_timeProvider.AdvanceTime(TimeSpan.FromSeconds(2));
_timeProvider.Advance(TimeSpan.FromSeconds(2));
health.Add(metrics.GetHealthInfo());
}

_timeProvider.AdvanceTime(TimeSpan.FromSeconds(2));
_timeProvider.Advance(TimeSpan.FromSeconds(2));
health.Add(metrics.GetHealthInfo());

health[0].Should().Be(new HealthInfo(2, 0.5));
Expand All @@ -76,11 +78,11 @@ public void GetHealthInfo_EnsureWindowCapacityRespected()
for (int i = 0; i < _windows; i++)
{
metrics.IncrementSuccess();
_timeProvider.AdvanceTime(delay);
_timeProvider.Advance(delay);
}

metrics.GetHealthInfo().Throughput.Should().Be(9);
_timeProvider.AdvanceTime(delay);
_timeProvider.Advance(delay);
metrics.GetHealthInfo().Throughput.Should().Be(8);
}

Expand All @@ -105,10 +107,10 @@ public void GetHealthInfo_SamplingDurationRespected(bool variance)
metrics.IncrementSuccess();
metrics.IncrementSuccess();

_timeProvider.AdvanceTime(_samplingDuration + (variance ? TimeSpan.FromMilliseconds(1) : TimeSpan.Zero));
_timeProvider.Advance(_samplingDuration + (variance ? TimeSpan.FromMilliseconds(1) : TimeSpan.Zero));

metrics.GetHealthInfo().Should().Be(new HealthInfo(0, 0));
}

private RollingHealthMetrics Create() => new(_samplingDuration, _windows, _timeProvider.Object);
private RollingHealthMetrics Create() => new(_samplingDuration, _windows, _timeProvider);
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
using Microsoft.Extensions.Time.Testing;
using Polly.CircuitBreaker.Health;

namespace Polly.Core.Tests.CircuitBreaker.Health;

public class SingleHealthMetricsTests
{
private readonly MockTimeProvider _timeProvider;
private readonly FakeTimeProvider _timeProvider;

public SingleHealthMetricsTests() => _timeProvider = new MockTimeProvider().SetupUtcNow();
public SingleHealthMetricsTests() => _timeProvider = new FakeTimeProvider();

[Fact]
public void Ctor_EnsureDefaults()
{
var metrics = new SingleHealthMetrics(TimeSpan.FromMilliseconds(100), _timeProvider.Object);
var metrics = new SingleHealthMetrics(TimeSpan.FromMilliseconds(100), _timeProvider);
var health = metrics.GetHealthInfo();

health.FailureRate.Should().Be(0);
Expand All @@ -20,7 +22,7 @@ public void Ctor_EnsureDefaults()
[Fact]
public void Increment_Ok()
{
var metrics = new SingleHealthMetrics(TimeSpan.FromMilliseconds(100), _timeProvider.Object);
var metrics = new SingleHealthMetrics(TimeSpan.FromMilliseconds(100), _timeProvider);

metrics.IncrementFailure();
metrics.IncrementSuccess();
Expand All @@ -37,7 +39,7 @@ public void Increment_Ok()
[Fact]
public void Reset_Ok()
{
var metrics = new SingleHealthMetrics(TimeSpan.FromMilliseconds(100), _timeProvider.Object);
var metrics = new SingleHealthMetrics(TimeSpan.FromMilliseconds(100), _timeProvider);

metrics.IncrementSuccess();
metrics.Reset();
Expand All @@ -48,12 +50,12 @@ public void Reset_Ok()
[Fact]
public void SamplingDurationRespected_Ok()
{
var metrics = new SingleHealthMetrics(TimeSpan.FromMilliseconds(100), _timeProvider.Object);
var metrics = new SingleHealthMetrics(TimeSpan.FromMilliseconds(100), _timeProvider);

metrics.IncrementSuccess();
metrics.IncrementSuccess();

_timeProvider.AdvanceTime(TimeSpan.FromMilliseconds(100));
_timeProvider.Advance(TimeSpan.FromMilliseconds(100));

metrics.GetHealthInfo().Throughput.Should().Be(0);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Microsoft.Extensions.Time.Testing;
using Polly.Utils;

namespace Polly.Core.Tests;
Expand Down Expand Up @@ -28,7 +29,7 @@ public void Properties_GetSet_Ok()
_builder.BuilderName = "dummy";
_builder.BuilderName.Should().Be("dummy");

var timeProvider = new MockTimeProvider().Object;
var timeProvider = new FakeTimeProvider();
_builder.TimeProvider = timeProvider;
_builder.TimeProvider.Should().Be(timeProvider);

Expand Down
Loading

0 comments on commit 195c40a

Please sign in to comment.