diff --git a/CHANGELOG.md b/CHANGELOG.md index 44de2aa5403..d672cfdc7c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## 5.3.0 - Fix ExecuteAndCapture() usage with PolicyWrap - Allow Fallback delegates to take execution Context +- Provide IReadOnlyPolicyRegistry interface ## 5.2.0 - Add PolicyRegistry for storing and retrieving policies. diff --git a/README.md b/README.md index ecbb9f7769f..32e24ffe2ef 100644 --- a/README.md +++ b/README.md @@ -734,7 +734,7 @@ registry["StandardHttpResilience"] = myStandardHttpResiliencePolicy; // Pass the registry instance to usage sites by DI, perhaps public class MyServiceGateway { - public void MyServiceGateway(..., IPolicyRegistry registry, ...) + public void MyServiceGateway(..., IReadOnlyPolicyRegistry registry, ...) { ... } @@ -905,6 +905,7 @@ For details of changes by release see the [change log](https://github.com/App-vN * [@reisenberger](https://github.com/reisenberger) - Add mutable Context and extra overloads taking Context. Allows different parts of a policy execution to exchange data via the mutable Context travelling with each execution. * [@ankitbko](https://github.com/ankitbko) - Add PolicyRegistry for storing and retrieving policies. * [@reisenberger](https://github.com/reisenberger) - Add interfaces by policy type and execution type. +* [@seanfarrow](https://github.com/SeanFarrow) - Add IReadOnlyPolicyRegistry interface. # Sample Projects diff --git a/src/Polly.Net40Async.nuspec b/src/Polly.Net40Async.nuspec index e134b39f0cc..810a3655deb 100644 --- a/src/Polly.Net40Async.nuspec +++ b/src/Polly.Net40Async.nuspec @@ -19,6 +19,7 @@ --------------------- - Fix ExecuteAndCapture() usage with PolicyWrap - Allow Fallback delegates to take execution Context + - Provide IReadOnlyPolicyRegistry interface 5.2.0 --------------------- diff --git a/src/Polly.Shared/Polly.Shared.projitems b/src/Polly.Shared/Polly.Shared.projitems index 62a9b94ddd8..13c570b91d7 100644 --- a/src/Polly.Shared/Polly.Shared.projitems +++ b/src/Polly.Shared/Polly.Shared.projitems @@ -77,6 +77,7 @@ + diff --git a/src/Polly.Shared/Registry/IPolicyRegistry.cs b/src/Polly.Shared/Registry/IPolicyRegistry.cs index 1d00ea2e159..bd9e0919fb7 100644 --- a/src/Polly.Shared/Registry/IPolicyRegistry.cs +++ b/src/Polly.Shared/Registry/IPolicyRegistry.cs @@ -8,7 +8,7 @@ namespace Polly.Registry /// Represents a collection of policies keyed by . /// /// The type of keys in the policy registry. - public interface IPolicyRegistry + public interface IPolicyRegistry : IReadOnlyPolicyRegistry { /// /// Adds an element with the provided key and policy to the registry. @@ -21,49 +21,15 @@ public interface IPolicyRegistry void Add(TKey key, TPolicy policy) where TPolicy : IsPolicy; /// - /// Gets of sets the with the specified key. - /// To retrieve a policy directly as a particular Policy type or Policy interface (avoiding a cast), use the method. + /// Gets or sets the with the specified key. + /// To retrieve a policy directly as a particular Policy type or Policy interface (avoiding a cast), use the method. /// /// The key of the value to get or set. /// is null. /// The given key was not present in the dictionary. /// The value associated with the specified key. - IsPolicy this[TKey key] { get; set; } - - /// - /// Gets the policy stored under the provided key, casting to . - /// - /// The type of Policy. - /// The policy stored in the registry under the given key. - /// is null. - TPolicy Get(TKey key) where TPolicy : IsPolicy; - - /// - /// Gets the policy stored under the provided key, casting to . - /// - /// The key of the policy to get. - /// - /// This method returns the policy associated with the specified , if the - /// key is found; otherwise null. - /// This parameter is passed uninitialized. - /// - /// The type of Policy. - /// True if Policy exists for the provided Key. False otherwise. - bool TryGet(TKey key, out TPolicy policy) where TPolicy : IsPolicy; - - /// - /// Total number of policies in the registry. - /// - int Count { get; } - - /// - /// Determines whether the specified exists. - /// - /// The Key to locate in the registry - /// True if exists otherwise false - /// is null - bool ContainsKey(TKey key); - + new IsPolicy this[TKey key] { get; set; } + /// /// Removes the specified from the registry. /// diff --git a/src/Polly.Shared/Registry/IReadOnlyPolicyRegistry.cs b/src/Polly.Shared/Registry/IReadOnlyPolicyRegistry.cs new file mode 100644 index 00000000000..4ce45d920cd --- /dev/null +++ b/src/Polly.Shared/Registry/IReadOnlyPolicyRegistry.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using Polly; + +namespace Polly.Registry +{ + /// + /// Represents a read-only collection of policies keyed by . + /// + /// The type of keys in the policy registry. + public interface IReadOnlyPolicyRegistry + { + /// + /// Gets the with the specified key. + /// To retrieve a policy directly as a particular Policy type or Policy interface (avoiding a cast), use the method. + /// + /// The key of the value to get or set. + /// is null. + /// The given key was not present in the dictionary. + /// The value associated with the specified key. + IsPolicy this[TKey key] { get; } + + /// + /// Gets the policy stored under the provided key, casting to . + /// + /// The type of Policy. + /// The policy stored in the registry under the given key. + /// is null. + TPolicy Get(TKey key) where TPolicy : IsPolicy; + + /// + /// Gets the policy stored under the provided key, casting to . + /// + /// The key of the policy to get. + /// + /// This method returns the policy associated with the specified , if the + /// key is found; otherwise null. + /// This parameter is passed uninitialized. + /// + /// The type of Policy. + /// True if Policy exists for the provided Key. False otherwise. + bool TryGet(TKey key, out TPolicy policy) where TPolicy : IsPolicy; + + /// + /// Total number of policies in the registry. + /// + int Count { get; } + + /// + /// Determines whether the specified exists. + /// + /// The Key to locate in the registry + /// True if exists otherwise false + /// is null + bool ContainsKey(TKey key); + } +} \ No newline at end of file diff --git a/src/Polly.SharedSpecs/Polly.SharedSpecs.projitems b/src/Polly.SharedSpecs/Polly.SharedSpecs.projitems index fd80c97db71..e993da5ce00 100644 --- a/src/Polly.SharedSpecs/Polly.SharedSpecs.projitems +++ b/src/Polly.SharedSpecs/Polly.SharedSpecs.projitems @@ -53,6 +53,7 @@ + diff --git a/src/Polly.SharedSpecs/Registry/IReadOnlyPolicyRegistrySpecs.cs b/src/Polly.SharedSpecs/Registry/IReadOnlyPolicyRegistrySpecs.cs new file mode 100644 index 00000000000..065e633f185 --- /dev/null +++ b/src/Polly.SharedSpecs/Registry/IReadOnlyPolicyRegistrySpecs.cs @@ -0,0 +1,258 @@ +using System; +using System.Collections.Generic; +using System.Text; +using FluentAssertions; +using Polly.Registry; +using Polly.Specs.Helpers; +using Xunit; + +namespace Polly.Specs.Registry +{ + public class IReadOnlyPolicyRegistrySpecs + { + IPolicyRegistry _registry; + + IReadOnlyPolicyRegistry ReadOnlyRegistry { get{ return _registry; } } + + public IReadOnlyPolicyRegistrySpecs() + { + _registry = new PolicyRegistry(); + } + + #region Tests for retrieving policy + + [Fact] + public void Should_be_able_to_retrieve_stored_Policy_using_TryGet() + { + Policy policy = Policy.NoOp(); + string key = Guid.NewGuid().ToString(); + Policy outPolicy = null; + + _registry.Add(key, policy); + ReadOnlyRegistry.TryGet(key, out outPolicy).Should().BeTrue(); + outPolicy.Should().BeSameAs(policy); + } + + [Fact] + public void Should_be_able_to_retrieve_stored_PolicyTResult_using_TryGet() + { + Policy policy = Policy.HandleResult(ResultPrimitive.Fault).Retry(); + string key = Guid.NewGuid().ToString(); + Policy outPolicy = null; + + _registry.Add(key, policy); + ReadOnlyRegistry.TryGet(key, out outPolicy).Should().BeTrue(); + outPolicy.Should().BeSameAs(policy); + } + + [Fact] + public void Should_be_able_to_retrieve_stored_Policy_by_interface_using_TryGet() + { + ISyncPolicy policy = Policy.HandleResult(ResultPrimitive.Fault).Retry(); + string key = Guid.NewGuid().ToString(); + ISyncPolicy outPolicy = null; + + _registry.Add(key, policy); + ReadOnlyRegistry.TryGet(key, out outPolicy).Should().BeTrue(); + outPolicy.Should().BeSameAs(policy); + } + + [Fact] + public void Should_be_able_to_retrieve_stored_Policy_using_Get() + { + Policy policy = Policy.NoOp(); + string key = Guid.NewGuid().ToString(); + + _registry.Add(key, policy); + ReadOnlyRegistry.Get(key).Should().BeSameAs(policy); + } + + [Fact] + public void Should_be_able_to_retrieve_stored_PolicyTResult_using_Get() + { + Policy policy = Policy.HandleResult(ResultPrimitive.Fault).Retry(); + string key = Guid.NewGuid().ToString(); + + _registry.Add(key, policy); + ReadOnlyRegistry.Get>(key).Should().BeSameAs(policy); + } + + [Fact] + public void Should_be_able_to_retrieve_stored_Policy_by_interface_using_Get() + { + ISyncPolicy policy = Policy.HandleResult(ResultPrimitive.Fault).Retry(); + string key = Guid.NewGuid().ToString(); + + _registry.Add(key, policy); + ReadOnlyRegistry.Get>(key).Should().BeSameAs(policy); + } + + [Fact] + public void Should_be_able_to_retrieve_stored_Policy_using_Indexer() + { + Policy policy = Policy.NoOp(); + string key = Guid.NewGuid().ToString(); + + _registry.Add(key, policy); + ReadOnlyRegistry[key].Should().BeSameAs(policy); + } + + [Fact] + public void Should_be_able_to_retrieve_stored_PolicyTResult_using_Indexer() + { + Policy policy = Policy.HandleResult(ResultPrimitive.Fault).Retry(); + string key = Guid.NewGuid().ToString(); + + _registry.Add(key, policy); + ReadOnlyRegistry[key].Should().BeSameAs(policy); + } + + [Fact] + public void Should_be_able_to_retrieve_stored_Policy_by_interface_using_Indexer() + { + ISyncPolicy policy = Policy.HandleResult(ResultPrimitive.Fault).Retry(); + string key = Guid.NewGuid().ToString(); + + _registry.Add(key, policy); + ReadOnlyRegistry[key].Should().BeSameAs(policy); + } + + [Fact] + public void Should_not_throw_while_retrieving_when_key_does_not_exist_using_TryGet() + { + string key = Guid.NewGuid().ToString(); + Policy outPolicy = null; + bool result = false; + + ReadOnlyRegistry.Invoking(r => result = r.TryGet(key, out outPolicy)) + .ShouldNotThrow(); + + result.Should().BeFalse(); + } + + [Fact] + public void Should_not_throw_while_retrieving_when_key_does_not_exist_using_TryGetPolicyTResult() + { + string key = Guid.NewGuid().ToString(); + Policy outPolicy = null; + bool result = false; + + ReadOnlyRegistry.Invoking(r => result = r.TryGet(key, out outPolicy)) + .ShouldNotThrow(); + + result.Should().BeFalse(); + } + + [Fact] + public void Should_not_throw_while_retrieving_when_key_does_not_exist_using_TryGetPolicy_by_interface() + { + string key = Guid.NewGuid().ToString(); + ISyncPolicy outPolicy = null; + bool result = false; + + ReadOnlyRegistry.Invoking(r => result = r.TryGet>(key, out outPolicy)) + .ShouldNotThrow(); + + result.Should().BeFalse(); + } + + [Fact] + public void Should_throw_while_retrieving_using_Get_when_key_does_not_exist() + { + string key = Guid.NewGuid().ToString(); + Policy policy = null; + ReadOnlyRegistry.Invoking(r => policy = r.Get(key)) + .ShouldThrow(); + } + + [Fact] + public void Should_throw_while_retrieving_using_GetTResult_when_key_does_not_exist() + { + string key = Guid.NewGuid().ToString(); + Policy policy = null; + ReadOnlyRegistry.Invoking(r => policy = r.Get>(key)) + .ShouldThrow(); + } + + [Fact] + public void Should_throw_while_retrieving_using_Get_by_interface_when_key_does_not_exist() + { + string key = Guid.NewGuid().ToString(); + ISyncPolicy policy = null; + ReadOnlyRegistry.Invoking(r => policy = r.Get>(key)) + .ShouldThrow(); + } + + [Fact] + public void Should_throw_while_retrieving_when_key_does_not_exist_using_Indexer() + { + string key = Guid.NewGuid().ToString(); + IsPolicy outPolicy = null; + ReadOnlyRegistry.Invoking(r => outPolicy = r[key]) + .ShouldThrow(); + } + + + [Fact] + public void Should_throw_when_retrieving_using_Get_when_key_is_null() + { + string key = null; + Policy policy = null; + ReadOnlyRegistry.Invoking(r => policy = r.Get(key)) + .ShouldThrow(); + } + + [Fact] + public void Should_throw_when_retrieving_using_GetTResult_when_key_is_null() + { + string key = null; + Policy policy = null; + ReadOnlyRegistry.Invoking(r => policy = r.Get>(key)) + .ShouldThrow(); + } + + [Fact] + public void Should_throw_when_retrieving_using_Get_by_interface_when_key_is_null() + { + string key = null; + ISyncPolicy policy = null; + ReadOnlyRegistry.Invoking(r => policy = r.Get>(key)) + .ShouldThrow(); + } + + [Fact] + public void Should_throw_when_retrieving_using_Indexer_when_key_is_null() + { + string key = null; + IsPolicy policy = null; + ReadOnlyRegistry.Invoking(r => policy = r[key]) + .ShouldThrow(); + } + #endregion + + #region Tests for checking if key exists + + [Fact] + public void Should_be_able_to_check_if_key_exists() + { + Policy policy = Policy.NoOp(); + string key = Guid.NewGuid().ToString(); + + _registry.Add(key, policy); + ReadOnlyRegistry.ContainsKey(key).Should().BeTrue(); + + string key2 = Guid.NewGuid().ToString(); + ReadOnlyRegistry.ContainsKey(key2).Should().BeFalse(); + } + + [Fact] + public void Should_throw_when_checking_if_key_exists_when_key_is_null() + { + string key = null; + ReadOnlyRegistry.Invoking(r => r.ContainsKey(key)) + .ShouldThrow(); + } + #endregion + + } +} diff --git a/src/Polly.SharedSpecs/Registry/PolicyRegistrySpecs.cs b/src/Polly.SharedSpecs/Registry/PolicyRegistrySpecs.cs index 856e6d306b6..1636eaa7af9 100644 --- a/src/Polly.SharedSpecs/Registry/PolicyRegistrySpecs.cs +++ b/src/Polly.SharedSpecs/Registry/PolicyRegistrySpecs.cs @@ -419,6 +419,7 @@ public void Should_throw_when_removing_Policy_when_key_is_null() #endregion #region Tests for checking if key exists + [Fact] public void Should_be_able_to_check_if_key_exists() { diff --git a/src/Polly.nuspec b/src/Polly.nuspec index bca6a2390c5..43cb5d6655d 100644 --- a/src/Polly.nuspec +++ b/src/Polly.nuspec @@ -15,6 +15,12 @@ v5.0 is a major release with significant new resilience policies: Timeout; Bulkhead Isolation; Fallback; and PolicyWrap. See release notes back to v5.0.0 for full details. v5.0.5 includes important circuit-breaker fixes. + 5.3.0 + --------------------- + - Fix ExecuteAndCapture() usage with PolicyWrap + - Allow Fallback delegates to take execution Context + - Provide IReadOnlyPolicyRegistry interface + 5.2.0 --------------------- - Add PolicyRegistry for storing and retrieving policies.