Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce unit-tests for issues fixed in v8 #1157

Merged
merged 12 commits into from
May 2, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class HedgingResilienceStrategyTests : IDisposable
private const string Failure = "Failure";

private static readonly TimeSpan LongDelay = TimeSpan.FromDays(1);
private static readonly TimeSpan AssertTimeout = TimeSpan.FromSeconds(10);
private static readonly TimeSpan AssertTimeout = TimeSpan.FromSeconds(15);

private readonly HedgingStrategyOptions _options = new();
private readonly List<IResilienceArguments> _events = new();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using Polly.CircuitBreaker;

namespace Polly.Core.Tests.Issues;

public partial class IssuesTests
{
[Fact]
public void CircuitBreakerStateSharing_959()
{
var options = new AdvancedCircuitBreakerStrategyOptions
{
FailureThreshold = 1,
MinimumThroughput = 10
};

// handle int results
options.ShouldHandle.HandleResult(-1);

// handle string results
options.ShouldHandle.HandleResult("error");

// create the strategy
var strategy = new ResilienceStrategyBuilder { TimeProvider = TimeProvider.Object }.AddAdvancedCircuitBreaker(options).Build();

// now trigger the circuit breaker by evaluating multiple result types
for (int i = 0; i < 5; i++)
{
strategy.Execute(_ => -1);
strategy.Execute(_ => "error");
}

// now the circuit breaker should be open
strategy.Invoking(s => s.Execute(_ => 0)).Should().Throw<BrokenCircuitException>();
strategy.Invoking(s => s.Execute(_ => "valid-result")).Should().Throw<BrokenCircuitException>();

// now wait for recovery
TimeProvider.AdvanceTime(options.BreakDuration);

// OK, circuit is closed now
strategy.Execute(_ => 0);
strategy.Execute(_ => "valid-result");
}
}
30 changes: 30 additions & 0 deletions src/Polly.Core.Tests/Issues/IssuesTests.FlowingContext_849.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Polly.Retry;

namespace Polly.Core.Tests.Issues;

public partial class IssuesTests
{
[Fact]
public void FlowingContext_849()
{
var contextChecked = false;
var retryOptions = new RetryStrategyOptions();

// configure the predicate and use the context
retryOptions.ShouldRetry.HandleResult<int>((_, args) =>
{
// access the context to evaluate the retry
ResilienceContext context = args.Context;
context.Should().NotBeNull();
contextChecked = true;
return false;
});

var strategy = new ResilienceStrategyBuilder().AddRetry(retryOptions).Build();

// execute the retry
strategy.Execute(_ => 0);

contextChecked.Should().BeTrue();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using Polly.Retry;

namespace Polly.Core.Tests.Issues;

public partial class IssuesTests
{
[Fact]
public void HandleMultipleResults_898()
{
var isRetryKey = new ResiliencePropertyKey<bool>("is-retry");
var options = new RetryStrategyOptions
{
BackoffType = RetryBackoffType.Constant,
RetryCount = 1,
BaseDelay = TimeSpan.FromMilliseconds(1),
};

// now add a callback updates the resilience context with the retry marker
options.OnRetry.Register((_, args) => args.Context.Properties.Set(isRetryKey, true));

// handle int results
options.ShouldRetry.HandleResult(-1);

// handle string results
options.ShouldRetry.HandleResult("error");

// create the strategy
var strategy = new ResilienceStrategyBuilder { TimeProvider = TimeProvider.Object }.AddRetry(options).Build();

// check that int-based results is retried
bool isRetry = false;
strategy.Execute(_ =>
{
if (isRetry)
{
return 0;
}

isRetry = true;
return -1;
}).Should().Be(0);

// check that string-based results is retried
isRetry = false;
strategy.Execute(_ =>
{
if (isRetry)
{
return "no-error";
}

isRetry = true;
return "error";
}).Should().Be("no-error");
}
}
6 changes: 6 additions & 0 deletions src/Polly.Core.Tests/Issues/IssuesTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Polly.Core.Tests.Issues;

public partial class IssuesTests
{
private FakeTimeProvider TimeProvider { get; } = new FakeTimeProvider().SetupUtcNow().SetupAnyDelay();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using Microsoft.Extensions.DependencyInjection;
using Polly.CircuitBreaker;
using Polly.Extensions.DependencyInjection;
using Polly.Registry;

namespace Polly.Core.Tests.Issues;

public partial class IssuesTests
{
[Fact]
public async Task OnCircuitBreakWithServiceProvider_796()
{
var contextChecked = false;
var options = new AdvancedCircuitBreakerStrategyOptions
{
FailureThreshold = 1,
MinimumThroughput = 10,
};

options.OnOpened.Register(async (_, args) =>
{
args.Context.Properties.GetValue(PollyDependencyInjectionKeys.ServiceProvider, null!).Should().NotBeNull();
contextChecked = true;

// do asynchronous call
await Task.Yield();
});

// handle string results
options.ShouldHandle.HandleResult("error");

// create the strategy
var serviceCollection = new ServiceCollection().AddResilienceStrategy("my-strategy", context =>
{
context.Builder
.AddStrategy(new ServiceProviderStrategy(context.ServiceProvider))
.AddAdvancedCircuitBreaker(options);
});

// retrieve the provider
var strategyProvider = serviceCollection.BuildServiceProvider().GetRequiredService<ResilienceStrategyProvider<string>>();
var strategy = strategyProvider.Get("my-strategy");

// now trigger the circuit breaker by evaluating multiple result types
for (int i = 0; i < 10; i++)
{
await strategy.ExecuteAsync(_ => Task.FromResult("error"));
}

// now the circuit breaker should be open
await strategy.Invoking(s => s.ExecuteAsync(_ => Task.FromResult("valid-result"))).Should().ThrowAsync<BrokenCircuitException>();

// check that service provider was received in the context
contextChecked.Should().BeTrue();
}

private class ServiceProviderStrategy : ResilienceStrategy
{
private readonly IServiceProvider _serviceProvider;

public ServiceProviderStrategy(IServiceProvider serviceProvider) => _serviceProvider = serviceProvider;

protected override ValueTask<TResult> ExecuteCoreAsync<TResult, TState>(Func<ResilienceContext, TState, ValueTask<TResult>> callback, ResilienceContext context, TState state)
{
context.Properties.Set(PollyDependencyInjectionKeys.ServiceProvider, _serviceProvider);
return callback(context, state);
}
}
}
10 changes: 10 additions & 0 deletions src/Polly.Extensions.Tests/Issues/IssuesTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Microsoft.Extensions.DependencyInjection;
using Polly.CircuitBreaker;
using Polly.Extensions.DependencyInjection;
using Polly.Registry;

namespace Polly.Core.Tests.Issues;

public partial class IssuesTests
{
}