From 5e71c23a1443bbfded8894d03d9d45a8596a3ec7 Mon Sep 17 00:00:00 2001
From: Martin Costello <martin@martincostello.com>
Date: Wed, 14 Apr 2021 18:31:27 +0100
Subject: [PATCH] Update Polly and support IConcurrentPolicyRegistry<string>
 (#31708)

---
 eng/Versions.props                            |  2 +-
 .../PollyServiceCollectionExtensions.cs       | 26 ++++++---
 .../PollyHttpClientBuilderExtensionsTest.cs   | 55 +++++++++++++++++++
 3 files changed, 73 insertions(+), 10 deletions(-)

diff --git a/eng/Versions.props b/eng/Versions.props
index 3ae7ae758ab..5f33d247890 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -246,7 +246,7 @@
     <NSwagApiDescriptionClientVersion>13.0.4</NSwagApiDescriptionClientVersion>
     <PlaywrightSharpVersion>0.192.0</PlaywrightSharpVersion>
     <PollyExtensionsHttpVersion>3.0.0</PollyExtensionsHttpVersion>
-    <PollyVersion>7.1.0</PollyVersion>
+    <PollyVersion>7.2.2</PollyVersion>
     <SeleniumSupportVersion>4.0.0-beta1</SeleniumSupportVersion>
     <SeleniumWebDriverChromeDriverVersion>89.0.4389.2300-beta</SeleniumWebDriverChromeDriverVersion>
     <SeleniumWebDriverVersion>4.0.0-beta1</SeleniumWebDriverVersion>
diff --git a/src/HttpClientFactory/Polly/src/DependencyInjection/PollyServiceCollectionExtensions.cs b/src/HttpClientFactory/Polly/src/DependencyInjection/PollyServiceCollectionExtensions.cs
index 6fe049d1172..c9e080c4faf 100644
--- a/src/HttpClientFactory/Polly/src/DependencyInjection/PollyServiceCollectionExtensions.cs
+++ b/src/HttpClientFactory/Polly/src/DependencyInjection/PollyServiceCollectionExtensions.cs
@@ -1,4 +1,4 @@
-// Licensed to the .NET Foundation under one or more agreements.
+// Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
@@ -8,15 +8,15 @@ using Polly.Registry;
 namespace Microsoft.Extensions.DependencyInjection
 {
     /// <summary>
-   /// Provides convenience extension methods to register <see cref="IPolicyRegistry{String}"/> and
-   /// <see cref="IReadOnlyPolicyRegistry{String}"/> in the service collection.
+    /// Provides convenience extension methods to register <see cref="IPolicyRegistry{String}"/> and
+    /// <see cref="IReadOnlyPolicyRegistry{String}"/> in the service collection.
     /// </summary>
     public static class PollyServiceCollectionExtensions
     {
         /// <summary>
         /// Registers an empty <see cref="PolicyRegistry"/> in the service collection with service types
-        /// <see cref="IPolicyRegistry{String}"/>, and <see cref="IReadOnlyPolicyRegistry{String}"/> and returns
-        /// the newly created registry.
+        /// <see cref="IPolicyRegistry{String}"/>, <see cref="IReadOnlyPolicyRegistry{String}"/>, and
+        /// <see cref="IConcurrentPolicyRegistry{String}"/> and returns the newly created registry.
         /// </summary>
         /// <param name="services">The <see cref="IServiceCollection"/>.</param>
         /// <returns>The newly created <see cref="IPolicyRegistry{String}"/>.</returns>
@@ -30,6 +30,8 @@ namespace Microsoft.Extensions.DependencyInjection
             // Create an empty registry, register and return it as an instance. This is the best way to get a
             // single instance registered using both interfaces.
             var registry = new PolicyRegistry();
+
+            services.AddSingleton<IConcurrentPolicyRegistry<string>>(registry);
             services.AddSingleton<IPolicyRegistry<string>>(registry);
             services.AddSingleton<IReadOnlyPolicyRegistry<string>>(registry);
 
@@ -38,8 +40,8 @@ namespace Microsoft.Extensions.DependencyInjection
 
         /// <summary>
         /// Registers the provided <see cref="IPolicyRegistry{String}"/> in the service collection with service types
-        /// <see cref="IPolicyRegistry{String}"/>, and <see cref="IReadOnlyPolicyRegistry{String}"/> and returns
-        /// the provided registry.
+        /// <see cref="IPolicyRegistry{String}"/>, <see cref="IReadOnlyPolicyRegistry{String}"/>, and
+        /// <see cref="IConcurrentPolicyRegistry{String}"/> and returns the provided registry.
         /// </summary>
         /// <param name="services">The <see cref="IServiceCollection"/>.</param>
         /// <param name="registry">The <see cref="IPolicyRegistry{String}"/>.</param>
@@ -59,13 +61,18 @@ namespace Microsoft.Extensions.DependencyInjection
             services.AddSingleton<IPolicyRegistry<string>>(registry);
             services.AddSingleton<IReadOnlyPolicyRegistry<string>>(registry);
 
+            if (registry is IConcurrentPolicyRegistry<string> concurrentRegistry)
+            {
+                services.AddSingleton<IConcurrentPolicyRegistry<string>>(concurrentRegistry);
+            }
+
             return registry;
         }
 
         /// <summary>
         /// Registers an empty <see cref="PolicyRegistry"/> in the service collection with service types
-        /// <see cref="IPolicyRegistry{String}"/>, and <see cref="IReadOnlyPolicyRegistry{String}"/> and
-        /// uses the specified delegate to configure it.
+        /// <see cref="IPolicyRegistry{String}"/>, <see cref="IReadOnlyPolicyRegistry{String}"/>, and
+        /// <see cref="IConcurrentPolicyRegistry{String}"/> and uses the specified delegate to configure it.
         /// </summary>
         /// <param name="services">The <see cref="IServiceCollection"/>.</param>
         /// <param name="configureRegistry">A delegate that is used to configure an <see cref="IPolicyRegistry{String}"/>.</param>
@@ -93,6 +100,7 @@ namespace Microsoft.Extensions.DependencyInjection
                 return registry;
             });
 
+            services.AddSingleton<IConcurrentPolicyRegistry<string>>(serviceProvider => serviceProvider.GetRequiredService<PolicyRegistry>());
             services.AddSingleton<IPolicyRegistry<string>>(serviceProvider => serviceProvider.GetRequiredService<PolicyRegistry>());
             services.AddSingleton<IReadOnlyPolicyRegistry<string>>(serviceProvider => serviceProvider.GetRequiredService<PolicyRegistry>());
 
diff --git a/src/HttpClientFactory/Polly/test/DependencyInjection/PollyHttpClientBuilderExtensionsTest.cs b/src/HttpClientFactory/Polly/test/DependencyInjection/PollyHttpClientBuilderExtensionsTest.cs
index 94d3f82bfdf..0f30410379d 100644
--- a/src/HttpClientFactory/Polly/test/DependencyInjection/PollyHttpClientBuilderExtensionsTest.cs
+++ b/src/HttpClientFactory/Polly/test/DependencyInjection/PollyHttpClientBuilderExtensionsTest.cs
@@ -11,6 +11,7 @@ using System.Threading.Tasks;
 using Microsoft.Extensions.Http;
 using Microsoft.Extensions.Http.Logging;
 using Polly;
+using Polly.Registry;
 using Xunit;
 
 namespace Microsoft.Extensions.DependencyInjection
@@ -468,6 +469,60 @@ namespace Microsoft.Extensions.DependencyInjection
             Assert.Equal(HttpStatusCode.Created, response.StatusCode);
         }
 
+        [Fact]
+        public void AddPolicyHandlerFromRegistry_WithoutConfigureDelegate_AddsPolicyRegistries()
+        {
+            var serviceCollection = new ServiceCollection();
+
+            // Act
+            serviceCollection.AddPolicyRegistry();
+
+            var services = serviceCollection.BuildServiceProvider();
+            var registry = services.GetService<IPolicyRegistry<string>>();
+
+            // Assert
+            Assert.NotNull(registry);
+            Assert.Same(registry, services.GetService<IConcurrentPolicyRegistry<string>>());
+            Assert.Same(registry, services.GetService<IReadOnlyPolicyRegistry<string>>());
+        }
+
+        [Fact]
+        public void AddPolicyHandlerFromRegistry_WithRegistry_AddsPolicyRegistries()
+        {
+            var serviceCollection = new ServiceCollection();
+            var registry = new PolicyRegistry();
+
+            // Act
+            serviceCollection.AddPolicyRegistry(registry);
+
+            var services = serviceCollection.BuildServiceProvider();
+
+            // Assert
+            Assert.Same(registry, services.GetService<IConcurrentPolicyRegistry<string>>());
+            Assert.Same(registry, services.GetService<IPolicyRegistry<string>>());
+            Assert.Same(registry, services.GetService<IReadOnlyPolicyRegistry<string>>());
+        }
+
+        [Fact]
+        public void AddPolicyHandlerFromRegistry_WithConfigureDelegate_AddsPolicyRegistries()
+        {
+            var serviceCollection = new ServiceCollection();
+
+            // Act
+            serviceCollection.AddPolicyRegistry((serviceProvider, registry) =>
+            {
+                // No-op
+            });
+
+            var services = serviceCollection.BuildServiceProvider();
+            var registry = services.GetService<IPolicyRegistry<string>>();
+
+            // Assert
+            Assert.NotNull(registry);
+            Assert.Same(registry, services.GetService<IConcurrentPolicyRegistry<string>>());
+            Assert.Same(registry, services.GetService<IReadOnlyPolicyRegistry<string>>());
+        }
+
         // Throws an exception or fails on even numbered requests, otherwise succeeds.
         private class FaultyMessageHandler : DelegatingHandler
         {
-- 
GitLab