Skip to content

Commit 6397bb3

Browse files
ogailogail
authored andcommitted
Address CR comments
1 parent 56edc0c commit 6397bb3

File tree

5 files changed

+119
-13
lines changed

5 files changed

+119
-13
lines changed

src/ResourceManager/Common/Commands.ResourceManager.Common/Properties/Resources.Designer.cs

Lines changed: 28 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/ResourceManager/Common/Commands.ResourceManager.Common/Properties/Resources.resx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,15 @@ Select Y to enable data collection [Y/N]:</value>
151151
<data name="NoSubscriptionFound" xml:space="preserve">
152152
<value>The provided account {0} does not have access to any subscriptions. Please try logging in with different credentials.</value>
153153
</data>
154+
<data name="ResourceProviderRegisterAttempt" xml:space="preserve">
155+
<value>Attempting to register resource provider '{0}'</value>
156+
</data>
157+
<data name="ResourceProviderRegisterFailure" xml:space="preserve">
158+
<value>Failed to register resource provider '{0}'.Details: '{1}'</value>
159+
</data>
160+
<data name="ResourceProviderRegisterSuccessful" xml:space="preserve">
161+
<value>Succeeded to register resource provider '{0}'</value>
162+
</data>
154163
<data name="SubscriptionIdNotFound" xml:space="preserve">
155164
<value>The provided account {0} does not have access to subscription ID "{1}". Please try logging in with different credentials not a different subscription ID.</value>
156165
</data>
@@ -160,4 +169,4 @@ Select Y to enable data collection [Y/N]:</value>
160169
<data name="TenantNotFound" xml:space="preserve">
161170
<value>Tenant '{0}' was not found. Please verify that your account has access to this tenant.</value>
162171
</data>
163-
</root>
172+
</root>

src/ResourceManager/Common/Commands.ResourceManager.Common/RPRegistrationDelegatingHandler.cs

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,31 +19,34 @@
1919
using System.Text;
2020
using System.Threading;
2121
using System.Threading.Tasks;
22+
using Microsoft.Azure.Commands.ResourceManager.Common.Properties;
2223
using Microsoft.Azure.Common.Authentication;
2324
using Microsoft.Azure.Common.Authentication.Models;
2425
using Microsoft.Azure.Management.Resources;
2526
using Microsoft.Azure.Management.Resources.Models;
27+
using Microsoft.WindowsAzure.Commands.Utilities.Common;
2628

2729
namespace Microsoft.Azure.Common.Authentication.Models
2830
{
29-
public class RPRegistrationDelegatingHandler : DelegatingHandler
31+
public class RPRegistrationDelegatingHandler : DelegatingHandler, ICloneable
3032
{
33+
private const short RetryCount = 3;
34+
3135
/// <summary>
3236
/// Contains all providers we have attempted to register
3337
/// </summary>
3438
private HashSet<string> registeredProviders;
3539

3640
private Func<ResourceManagementClient> createClient;
3741

38-
private Action<string> writeVerbose;
39-
42+
private Action<string> writeDebug;
4043

4144
public ResourceManagementClient ResourceManagementClient { get; set; }
4245

43-
public RPRegistrationDelegatingHandler(Func<ResourceManagementClient> createClient, Action<string> writeVerbose)
46+
public RPRegistrationDelegatingHandler(Func<ResourceManagementClient> createClient, Action<string> writeDebug)
4447
{
4548
registeredProviders = new HashSet<string>();
46-
this.writeVerbose = writeVerbose;
49+
this.writeDebug = writeDebug;
4750
this.createClient = createClient;
4851
}
4952

@@ -57,21 +60,29 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
5760
var providerName = GetProviderName(request.RequestUri);
5861
if (!string.IsNullOrEmpty(providerName) && !registeredProviders.Contains(providerName))
5962
{
63+
// Force dispose for response messages to reclaim the used socket connection.
64+
responseMessage.Dispose();
6065
registeredProviders.Add(providerName);
6166
try
6267
{
63-
writeVerbose(string.Format("Attempting to register resource provider '{0}'", providerName));
68+
writeDebug(string.Format(Resources.ResourceProviderRegisterAttempt, providerName));
6469
ResourceManagementClient.Providers.Register(providerName);
6570
Provider provider = null;
71+
short retryCount = 0;
6672
do
6773
{
74+
if (retryCount++ > RetryCount)
75+
{
76+
throw new TimeoutException();
77+
}
6878
provider = ResourceManagementClient.Providers.Get(providerName).Provider;
79+
TestMockSupport.Delay(1000);
6980
} while (provider.RegistrationState != RegistrationState.Registered.ToString());
70-
writeVerbose(string.Format("Succeeded to register resource provider '{0}'", providerName));
81+
writeDebug(string.Format(Resources.ResourceProviderRegisterSuccessful, providerName));
7182
}
72-
catch
83+
catch (Exception e)
7384
{
74-
writeVerbose(string.Format("Failed to register resource provider '{0}'", providerName));
85+
writeDebug(string.Format(Resources.ResourceProviderRegisterFailure, providerName, e.Message));
7586
// Ignore RP registration errors.
7687
}
7788

@@ -99,5 +110,10 @@ private string GetProviderName(Uri requestUri)
99110
return (requestUri.Segments.Length > 7 && requestUri.Segments[5].ToLower() == "providers/") ?
100111
requestUri.Segments[6].ToLower().Trim('/') : null;
101112
}
113+
114+
public object Clone()
115+
{
116+
return new RPRegistrationDelegatingHandler(createClient, writeDebug);
117+
}
102118
}
103119
}

src/ResourceManager/Common/Commands.ScenarioTests.ResourceManager.Common/RMTestBase.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
using Microsoft.Azure.Common.Authentication;
2020
using Microsoft.Azure.Commands.ResourceManager.Common;
2121
using Microsoft.WindowsAzure.Commands.Common;
22+
using Microsoft.WindowsAzure.Commands.Utilities.Common;
2223

2324
namespace Microsoft.WindowsAzure.Commands.Test.Utilities.Common
2425
{
@@ -64,6 +65,7 @@ public void BaseSetup()
6465
}
6566

6667
AzureSession.AuthenticationFactory = new MockTokenAuthenticationFactory();
68+
TestMockSupport.RunningMocked = true;
6769
}
6870
}
6971
}

src/ResourceManager/Profile/Commands.Profile.Test/RPRegistrationDelegatingHandlerTests.cs

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,15 +181,67 @@ public void DoesNotInvokeRegistrationForIncompatibleUri()
181181
Assert.Equal(response.StatusCode, HttpStatusCode.Conflict);
182182
Assert.Equal(response.Content.ReadAsStringAsync().Result, "registered to use namespace");
183183
}
184+
185+
[Fact]
186+
public void DoesNotHangForLongRegistrationCalls()
187+
{
188+
// Setup
189+
Mock<ResourceManagementClient> mockClient = new Mock<ResourceManagementClient>();
190+
Mock<IProviderOperations> mockProvidersOperations = new Mock<IProviderOperations>();
191+
mockClient.Setup(f => f.Providers).Returns(mockProvidersOperations.Object);
192+
mockProvidersOperations.Setup(f => f.GetAsync(It.IsAny<string>(), It.IsAny<CancellationToken>())).Returns(
193+
(string rp, CancellationToken token) =>
194+
{
195+
ProviderGetResult r = new ProviderGetResult
196+
{
197+
Provider = new Provider
198+
{
199+
RegistrationState = RegistrationState.Pending.ToString()
200+
}
201+
};
202+
203+
return Task.FromResult(r);
204+
}
205+
);
206+
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, compatibleUri);
207+
Dictionary<HttpRequestMessage, List<HttpResponseMessage>> mapping = new Dictionary<HttpRequestMessage, List<HttpResponseMessage>>
208+
{
209+
{
210+
request, new List<HttpResponseMessage>
211+
{
212+
new HttpResponseMessage(HttpStatusCode.Conflict) { Content = new StringContent("registered to use namespace") },
213+
new HttpResponseMessage(HttpStatusCode.Conflict) { Content = new StringContent("registered to use namespace") }
214+
}
215+
}
216+
};
217+
List<string> msgs = new List<string>();
218+
RPRegistrationDelegatingHandler rpHandler = new RPRegistrationDelegatingHandler(() => mockClient.Object, s => msgs.Add(s))
219+
{
220+
InnerHandler = new MockResponseDelegatingHandler(mapping)
221+
};
222+
HttpClient httpClient = new HttpClient(rpHandler);
223+
224+
// Test
225+
HttpResponseMessage response = httpClient.SendAsync(request).Result;
226+
227+
// Assert
228+
Assert.True(msgs.Any(s => s.Equals("Failed to register resource provider 'microsoft.compute'.Details: 'The operation has timed out.'")));
229+
Assert.Equal(response.StatusCode, HttpStatusCode.Conflict);
230+
Assert.Equal(response.Content.ReadAsStringAsync().Result, "registered to use namespace");
231+
mockProvidersOperations.Verify(f => f.RegisterAsync("microsoft.compute", It.IsAny<CancellationToken>()), Times.AtMost(4));
232+
}
184233
}
185234

186235
public class MockResponseDelegatingHandler : DelegatingHandler
187236
{
188237
Dictionary<HttpRequestMessage, List<HttpResponseMessage>> mapping;
189238

239+
public int RequestsCount { get; set; }
240+
190241
public MockResponseDelegatingHandler(Dictionary<HttpRequestMessage, List<HttpResponseMessage>> mapping)
191242
{
192243
this.mapping = mapping;
244+
this.RequestsCount = 0;
193245
}
194246

195247
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
@@ -198,9 +250,9 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
198250
{
199251
var response = mapping[request].First();
200252
mapping[request].Remove(response);
253+
RequestsCount++;
201254
return response;
202255
});
203256
}
204-
205257
}
206-
}
258+
}

0 commit comments

Comments
 (0)