-
Notifications
You must be signed in to change notification settings - Fork 521
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added query param support and validation for export request. (#438)
Added query param support and validation for export request. We support (and require) _destinationType and _destinationConnectionSettings. Added a new ISecretStore and corresponding Azure KeyVault based implementation to store this information.
- Loading branch information
Showing
36 changed files
with
795 additions
and
177 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -285,7 +285,8 @@ | |
"permissions": { | ||
"secrets": [ | ||
"get", | ||
"list" | ||
"list", | ||
"set" | ||
] | ||
} | ||
} | ||
|
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
99 changes: 0 additions & 99 deletions
99
...t.Health.Fhir.Api.UnitTests/Features/Filters/ValidateExportHeadersFilterAttributeTests.cs
This file was deleted.
Oops, something went wrong.
207 changes: 207 additions & 0 deletions
207
...t.Health.Fhir.Api.UnitTests/Features/Filters/ValidateExportRequestFilterAttributeTests.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,207 @@ | ||
// ------------------------------------------------------------------------------------------------- | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. | ||
// ------------------------------------------------------------------------------------------------- | ||
|
||
using System.Collections.Generic; | ||
using Hl7.Fhir.Rest; | ||
using Microsoft.AspNetCore.Http; | ||
using Microsoft.AspNetCore.Http.Internal; | ||
using Microsoft.AspNetCore.Mvc; | ||
using Microsoft.AspNetCore.Mvc.Abstractions; | ||
using Microsoft.AspNetCore.Mvc.Filters; | ||
using Microsoft.AspNetCore.Routing; | ||
using Microsoft.Extensions.Options; | ||
using Microsoft.Extensions.Primitives; | ||
using Microsoft.Health.Fhir.Api.Features.Filters; | ||
using Microsoft.Health.Fhir.Core.Configs; | ||
using Microsoft.Health.Fhir.Core.Exceptions; | ||
using Microsoft.Health.Fhir.Core.Features; | ||
using Microsoft.Net.Http.Headers; | ||
using NSubstitute; | ||
using Xunit; | ||
|
||
namespace Microsoft.Health.Fhir.Api.UnitTests.Features.Filters | ||
{ | ||
public class ValidateExportRequestFilterAttributeTests | ||
{ | ||
private const string CorrectAcceptHeaderValue = ContentType.JSON_CONTENT_HEADER; | ||
private const string CorrectPreferHeaderValue = "respond-async"; | ||
private const string PreferHeaderName = "Prefer"; | ||
private const string SupportedDestinationType = "AnySupportedDestinationType"; | ||
|
||
[Theory] | ||
[InlineData("application/fhir+xml")] | ||
[InlineData("application/xml")] | ||
[InlineData("text/xml")] | ||
[InlineData("application/json")] | ||
[InlineData("*/*")] | ||
public void GiveARequestWithInvalidAcceptHeader_WhenGettingAnExportOperationRequest_ThenARequestNotValidExceptionShouldBeThrown(string acceptHeader) | ||
{ | ||
var filter = GetFilter(); | ||
var context = CreateContextWithParams(); | ||
|
||
context.HttpContext.Request.Headers.Add(HeaderNames.Accept, acceptHeader); | ||
|
||
Assert.Throws<RequestNotValidException>(() => filter.OnActionExecuting(context)); | ||
} | ||
|
||
[Fact] | ||
public void GiveARequestWithNoAcceptHeader_WhenGettingAnExportOperationRequest_ThenARequestNotValidExceptionShouldBeThrown() | ||
{ | ||
var filter = GetFilter(); | ||
var context = CreateContextWithParams(); | ||
|
||
context.HttpContext.Request.Headers.Add(PreferHeaderName, CorrectPreferHeaderValue); | ||
|
||
Assert.Throws<RequestNotValidException>(() => filter.OnActionExecuting(context)); | ||
} | ||
|
||
[Theory] | ||
[InlineData("respond-async, wait = 10")] | ||
[InlineData("return-content")] | ||
[InlineData("*")] | ||
public void GiveARequestWithInvalidPreferHeader_WhenGettingAnExportOperationRequest_ThenARequestNotValidExceptionShouldBeThrown(string preferHeader) | ||
{ | ||
var filter = GetFilter(); | ||
var context = CreateContextWithParams(); | ||
|
||
context.HttpContext.Request.Headers.Add(PreferHeaderName, preferHeader); | ||
|
||
Assert.Throws<RequestNotValidException>(() => filter.OnActionExecuting(context)); | ||
} | ||
|
||
[Fact] | ||
public void GiveARequestWithNoPreferHeader_WhenGettingAnExportOperationRequest_ThenARequestNotValidExceptionShouldBeThrown() | ||
{ | ||
var filter = GetFilter(); | ||
var context = CreateContextWithParams(); | ||
|
||
context.HttpContext.Request.Headers.Add(HeaderNames.Accept, CorrectAcceptHeaderValue); | ||
|
||
Assert.Throws<RequestNotValidException>(() => filter.OnActionExecuting(context)); | ||
} | ||
|
||
[Fact] | ||
public void GiveARequestWithValidAcceptAndPreferHeader_WhenGettingAnExportOperationRequest_ThenTheResultIsSuccessful() | ||
{ | ||
var filter = GetFilter(); | ||
var context = CreateContextWithParams(); | ||
|
||
context.HttpContext.Request.Headers.Add(HeaderNames.Accept, CorrectAcceptHeaderValue); | ||
context.HttpContext.Request.Headers.Add(PreferHeaderName, CorrectPreferHeaderValue); | ||
|
||
filter.OnActionExecuting(context); | ||
} | ||
|
||
[Fact] | ||
public void GivenARequestWithCorrectHeadersAndMissingDestinationTypeParam_WhenGettingAnExportOperationRequest_ThenARequestNotValidExceptionShouldBeThrown() | ||
{ | ||
var filter = GetFilter(); | ||
var queryParams = new Dictionary<string, StringValues>() | ||
{ | ||
{ KnownQueryParameterNames.DestinationConnectionSettings, "destination" }, | ||
}; | ||
|
||
var context = CreateContextWithParams(queryParams); | ||
|
||
context.HttpContext.Request.Headers.Add(HeaderNames.Accept, CorrectAcceptHeaderValue); | ||
context.HttpContext.Request.Headers.Add(PreferHeaderName, CorrectPreferHeaderValue); | ||
|
||
Assert.Throws<RequestNotValidException>(() => filter.OnActionExecuting(context)); | ||
} | ||
|
||
[Fact] | ||
public void GivenARequestWithCorrectHeadersAndMissingDestinationConnectionParam_WhenGettingAnExportOperationRequest_ThenARequestNotValidExceptionShouldBeThrown() | ||
{ | ||
var filter = GetFilter(); | ||
var queryParams = new Dictionary<string, StringValues>() | ||
{ | ||
{ KnownQueryParameterNames.DestinationType, SupportedDestinationType }, | ||
}; | ||
|
||
var context = CreateContextWithParams(queryParams); | ||
|
||
context.HttpContext.Request.Headers.Add(HeaderNames.Accept, CorrectAcceptHeaderValue); | ||
context.HttpContext.Request.Headers.Add(PreferHeaderName, CorrectPreferHeaderValue); | ||
|
||
Assert.Throws<RequestNotValidException>(() => filter.OnActionExecuting(context)); | ||
} | ||
|
||
[Fact] | ||
public void GivenARequestWithCorrectHeadersAndDestinationTypeThatIsNotSupported_WhenGettingAnExportOperationRequest_ThenARequestNotValidExceptionShouldBeThrown() | ||
{ | ||
var filter = GetFilter(); | ||
var queryParams = new Dictionary<string, StringValues>() | ||
{ | ||
{ KnownQueryParameterNames.DestinationType, "Azure" }, | ||
{ KnownQueryParameterNames.DestinationConnectionSettings, "destination" }, | ||
}; | ||
|
||
var context = CreateContextWithParams(queryParams); | ||
|
||
context.HttpContext.Request.Headers.Add(HeaderNames.Accept, CorrectAcceptHeaderValue); | ||
context.HttpContext.Request.Headers.Add(PreferHeaderName, CorrectPreferHeaderValue); | ||
|
||
Assert.Throws<RequestNotValidException>(() => filter.OnActionExecuting(context)); | ||
} | ||
|
||
[Fact] | ||
public void GivenARequestWithCorrectHeadersAndUnsupportedQueryParameter_WhenGettingAnExportOperationRequest_ThenARequestNotValidExceptionShouldBeThrown() | ||
{ | ||
var filter = GetFilter(); | ||
var queryParams = new Dictionary<string, StringValues>() | ||
{ | ||
{ KnownQueryParameterNames.DestinationType, SupportedDestinationType }, | ||
{ KnownQueryParameterNames.DestinationConnectionSettings, "destination" }, | ||
{ KnownQueryParameterNames.Since, "forever" }, | ||
}; | ||
|
||
var context = CreateContextWithParams(queryParams); | ||
|
||
context.HttpContext.Request.Headers.Add(HeaderNames.Accept, CorrectAcceptHeaderValue); | ||
context.HttpContext.Request.Headers.Add(PreferHeaderName, CorrectPreferHeaderValue); | ||
|
||
Assert.Throws<RequestNotValidException>(() => filter.OnActionExecuting(context)); | ||
} | ||
|
||
private static ActionExecutingContext CreateContextWithParams(Dictionary<string, StringValues> queryParams = null) | ||
{ | ||
var context = new ActionExecutingContext( | ||
new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()), | ||
new List<IFilterMetadata>(), | ||
new Dictionary<string, object>(), | ||
FilterTestsHelper.CreateMockExportController()); | ||
|
||
if (queryParams == null) | ||
{ | ||
queryParams = new Dictionary<string, StringValues>(); | ||
queryParams.Add(KnownQueryParameterNames.DestinationType, SupportedDestinationType); | ||
queryParams.Add(KnownQueryParameterNames.DestinationConnectionSettings, "connectionString"); | ||
} | ||
|
||
context.HttpContext.Request.Query = new QueryCollection(queryParams); | ||
return context; | ||
} | ||
|
||
private static ValidateExportRequestFilterAttribute GetFilter(ExportJobConfiguration exportJobConfig = null) | ||
{ | ||
if (exportJobConfig == null) | ||
{ | ||
exportJobConfig = new ExportJobConfiguration(); | ||
exportJobConfig.Enabled = true; | ||
exportJobConfig.SupportedDestinations.Add(SupportedDestinationType); | ||
} | ||
|
||
var opConfig = new OperationsConfiguration() | ||
{ | ||
Export = exportJobConfig, | ||
}; | ||
|
||
IOptions<OperationsConfiguration> options = Substitute.For<IOptions<OperationsConfiguration>>(); | ||
options.Value.Returns(opConfig); | ||
|
||
return new ValidateExportRequestFilterAttribute(options); | ||
} | ||
} | ||
} |
Oops, something went wrong.