-
Notifications
You must be signed in to change notification settings - Fork 179
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update health check to handle concurrency (#3317)
* use leases for health check; update not found error * added blob type not supported * update unit tests to reflect new health check behavior * move exception extensions to core * write health check blob to different files, and set expiry time on write * update unit tests and add test for pipeline policy * remove unnecessary nuget package * update blob file store tests * remove comment in appsettings * Respond to PR comments * add invalidauthenticationinfo as customer error * respond to pr comments * add both regex options
- Loading branch information
1 parent
93c8eb2
commit 245e308
Showing
12 changed files
with
305 additions
and
52 deletions.
There are no files selected for viewing
115 changes: 115 additions & 0 deletions
115
...h.Dicom.Blob.UnitTests/Features/ExternalStore/ExternalStoreHealthExpiryHttpPolicyTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
// ------------------------------------------------------------------------------------------------- | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. | ||
// ------------------------------------------------------------------------------------------------- | ||
|
||
using System; | ||
using System.Linq; | ||
using Azure.Core; | ||
using Azure.Core.Pipeline; | ||
using Microsoft.Health.Dicom.Blob.Features.ExternalStore; | ||
using Microsoft.Health.Dicom.Blob.Utilities; | ||
using NSubstitute; | ||
using Xunit; | ||
|
||
namespace Microsoft.Health.Dicom.Blob.UnitTests.Features.ExternalStore; | ||
|
||
public class ExternalStoreHealthExpiryHttpPolicyTests | ||
{ | ||
private readonly ExternalBlobDataStoreConfiguration _blobDataStoreConfiguration; | ||
private readonly ExternalStoreHealthExpiryHttpPipelinePolicy _externalStoreHealthExpiryPolicy; | ||
|
||
private readonly MockRequest _request; | ||
private readonly HttpPipelinePolicy _mockPipeline = Substitute.For<HttpPipelinePolicy>(); | ||
|
||
public ExternalStoreHealthExpiryHttpPolicyTests() | ||
{ | ||
_blobDataStoreConfiguration = new ExternalBlobDataStoreConfiguration() | ||
{ | ||
BlobContainerUri = new Uri("https://myBlobStore.blob.core.net/myContainer"), | ||
StorageDirectory = "DICOM", | ||
HealthCheckFilePath = "healthCheck/health", | ||
HealthCheckFileExpiry = TimeSpan.FromMinutes(1), | ||
}; | ||
|
||
_request = new MockRequest(); | ||
_externalStoreHealthExpiryPolicy = new ExternalStoreHealthExpiryHttpPipelinePolicy(_blobDataStoreConfiguration); | ||
} | ||
|
||
[Theory] | ||
[InlineData("PUT")] | ||
[InlineData("POST")] | ||
[InlineData("PATCH")] | ||
public void GivenHealthCheckBlob_Proccess_AddsExpiryHeaders(string requestMethod) | ||
{ | ||
RequestUriBuilder requestUriBuilder = new RequestUriBuilder(); | ||
requestUriBuilder.Reset(new Uri($"https://myBlobStore.blob.core.net/myContainer/DICOM/healthCheck/health{Guid.NewGuid()}.txt")); | ||
|
||
_request.Uri = requestUriBuilder; | ||
_request.Method = RequestMethod.Parse(requestMethod); | ||
HttpMessage httpMessage = new HttpMessage(_request, new ResponseClassifier()); | ||
|
||
_externalStoreHealthExpiryPolicy.Process(httpMessage, new ReadOnlyMemory<HttpPipelinePolicy>(new HttpPipelinePolicy[] { _mockPipeline })); | ||
|
||
_request.MockHeaders.Single(h => h.Name == "x-ms-expiry-time" && h.Value == $"{_blobDataStoreConfiguration.HealthCheckFileExpiry.TotalMilliseconds}"); | ||
_request.MockHeaders.Single(h => h.Name == "x-ms-expiry-option" && h.Value == "RelativeToNow"); | ||
} | ||
|
||
[Theory] | ||
[InlineData("PUT")] | ||
[InlineData("POST")] | ||
[InlineData("PATCH")] | ||
[InlineData("GET")] | ||
[InlineData("DELETE")] | ||
public void GivenNonHealthCheckBlob_ProccessForAllRequestTypes_NoHeadersAdded(string requestMethod) | ||
{ | ||
RequestUriBuilder requestUriBuilder = new RequestUriBuilder(); | ||
requestUriBuilder.Reset(new Uri($"https://myBlobStore.blob.core.net/myContainer/DICOM/healthCheck/health{Guid.NewGuid()}.txt/anotherBlob")); | ||
|
||
_request.Uri = requestUriBuilder; | ||
_request.Method = RequestMethod.Parse(requestMethod); | ||
HttpMessage httpMessage = new HttpMessage(_request, new ResponseClassifier()); | ||
|
||
_externalStoreHealthExpiryPolicy.Process(httpMessage, new ReadOnlyMemory<HttpPipelinePolicy>(new HttpPipelinePolicy[] { _mockPipeline })); | ||
|
||
Assert.Empty(_request.MockHeaders); | ||
} | ||
|
||
[Theory] | ||
[InlineData("https://blob.com")] | ||
[InlineData("https://myBlobStore.blob.core.net/myContainer/DICOM/anotherDirectory/healthCheck/health00000000-0000-0000-0000-000000000000/anotherBlob")] | ||
[InlineData("https://myBlobStore.blob.core.net/myContainer/DICOM/anotherDirectory/healthCheck/health00000000-0000-0000-0000-000000000000.txt")] | ||
[InlineData("https://myBlobStore.blob.core.net/myContainer/DICOM/healthCheck/health00000000-0000-0000-0000-000000000000")] | ||
[InlineData("https://myBlobStore.blob.core.net/myContainer/DICOM/healthCheck/health")] | ||
[InlineData("https://myBlobStore.blob.core.net/myContainer/DICOM/healthCheck")] | ||
public void GivenNonHealthCheckBlob_ProccessDifferentBlobUris_NoHeadersAdded(string nonHealthCheckBlob) | ||
{ | ||
RequestUriBuilder requestUriBuilder = new RequestUriBuilder(); | ||
requestUriBuilder.Reset(new Uri(nonHealthCheckBlob)); | ||
|
||
_request.Uri = requestUriBuilder; | ||
_request.Method = RequestMethod.Put; | ||
HttpMessage httpMessage = new HttpMessage(_request, new ResponseClassifier()); | ||
|
||
_externalStoreHealthExpiryPolicy.Process(httpMessage, new ReadOnlyMemory<HttpPipelinePolicy>(new HttpPipelinePolicy[] { _mockPipeline })); | ||
|
||
Assert.Empty(_request.MockHeaders); | ||
} | ||
|
||
[Theory] | ||
[InlineData("GET")] | ||
[InlineData("DELETE")] | ||
public void GivenHealthCheckBlobReadOrDelete_Proccess_AddsExpiryHeaders(string requestMethod) | ||
{ | ||
RequestUriBuilder requestUriBuilder = new RequestUriBuilder(); | ||
requestUriBuilder.Reset(new Uri($"https://myBlobStore.blob.core.net/myContainer/DICOM/healthCheck/health{Guid.NewGuid()}.txt")); | ||
|
||
_request.Uri = requestUriBuilder; | ||
_request.Method = RequestMethod.Parse(requestMethod); | ||
HttpMessage httpMessage = new HttpMessage(_request, new ResponseClassifier()); | ||
|
||
_externalStoreHealthExpiryPolicy.Process(httpMessage, new ReadOnlyMemory<HttpPipelinePolicy>(new HttpPipelinePolicy[] { _mockPipeline })); | ||
|
||
Assert.Empty(_request.MockHeaders); | ||
} | ||
} |
45 changes: 45 additions & 0 deletions
45
src/Microsoft.Health.Dicom.Blob.UnitTests/Features/ExternalStore/MockRequest.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// ------------------------------------------------------------------------------------------------- | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. | ||
// ------------------------------------------------------------------------------------------------- | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.Linq; | ||
using Azure.Core; | ||
|
||
namespace Microsoft.Health.Dicom.Blob.UnitTests.Features.ExternalStore; | ||
|
||
internal class MockRequest : Request | ||
{ | ||
public MockRequest() | ||
{ | ||
MockHeaders = new List<HttpHeader>(); | ||
} | ||
|
||
public List<HttpHeader> MockHeaders { get; } | ||
|
||
public override string ClientRequestId { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } | ||
|
||
public override void Dispose() => throw new NotImplementedException(); | ||
|
||
protected override void AddHeader(string name, string value) | ||
{ | ||
MockHeaders.Add(new HttpHeader(name, value)); | ||
} | ||
|
||
protected override bool ContainsHeader(string name) | ||
{ | ||
return MockHeaders.Any(h => h.Name == name); | ||
} | ||
|
||
protected override IEnumerable<HttpHeader> EnumerateHeaders() | ||
{ | ||
return MockHeaders; | ||
} | ||
|
||
protected override bool RemoveHeader(string name) => throw new NotImplementedException(); | ||
protected override bool TryGetHeader(string name, [NotNullWhen(true)] out string value) => throw new NotImplementedException(); | ||
protected override bool TryGetHeaderValues(string name, [NotNullWhen(true)] out IEnumerable<string> values) => throw new NotImplementedException(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.