public async Task GivenATransactionBundleRequestWithNullUrl_WhenProcessing_ReturnsABadRequest() { var bundle = new Hl7.Fhir.Model.Bundle { Type = BundleType.Transaction, Entry = new List <EntryComponent> { new EntryComponent { Request = new RequestComponent { Method = HTTPVerb.PUT, Url = null, }, Resource = new Basic { Id = "test" }, }, }, }; _router.When(r => r.RouteAsync(Arg.Any <RouteContext>())) .Do(RouteAsyncFunction); var bundleRequest = new BundleRequest(bundle.ToResourceElement()); await Assert.ThrowsAsync <RequestNotValidException>(async() => await _bundleHandler.Handle(bundleRequest, default)); }
public async Task <BundleResponse> Handle(BundleRequest bundleRequest, CancellationToken cancellationToken) { var bundleResource = bundleRequest.Bundle.ToPoco <Hl7.Fhir.Model.Bundle>(); await FillRequestLists(bundleResource.Entry); if (bundleResource.Type == Hl7.Fhir.Model.Bundle.BundleType.Batch) { var responseBundle = new Hl7.Fhir.Model.Bundle { Type = Hl7.Fhir.Model.Bundle.BundleType.BatchResponse, }; await ExecuteAllRequests(responseBundle); return(new BundleResponse(responseBundle.ToResourceElement())); } else if (bundleResource.Type == Hl7.Fhir.Model.Bundle.BundleType.Transaction) { var responseBundle = new Hl7.Fhir.Model.Bundle { Type = Hl7.Fhir.Model.Bundle.BundleType.TransactionResponse, }; return(await ExecuteTransactionForAllRequests(responseBundle)); } throw new MethodNotAllowedException(string.Format(Api.Resources.InvalidBundleType, bundleResource.Type)); }
public async Task GivenABundleWithMultipleCalls_WhenProcessed_ThenANotificationWillBeEmitted(BundleType type, HTTPVerb method1, HTTPVerb method2, int code200s, int code404s) { var bundle = new Hl7.Fhir.Model.Bundle { Type = type, Entry = new List <EntryComponent> { new EntryComponent { Request = new RequestComponent { Method = method1, Url = "unused1", }, Resource = new Patient(), }, new EntryComponent { Request = new RequestComponent { Method = method2, Url = "unused2", }, Resource = new Patient(), }, }, }; _router.When(r => r.RouteAsync(Arg.Any <RouteContext>())) .Do(RouteAsyncFunction); BundleMetricsNotification notification = null; await _mediator.Publish(Arg.Do <BundleMetricsNotification>(note => notification = note), Arg.Any <CancellationToken>()); var bundleRequest = new BundleRequest(bundle.ToResourceElement()); BundleResponse bundleResponse = await _bundleHandler.Handle(bundleRequest, default); var bundleResource = bundleResponse.Bundle.ToPoco <Hl7.Fhir.Model.Bundle>(); Assert.Equal(type == BundleType.Batch ? BundleType.BatchResponse : BundleType.TransactionResponse, bundleResource.Type); Assert.Equal(2, bundleResource.Entry.Count); await _mediator.Received().Publish(Arg.Any <BundleMetricsNotification>(), Arg.Any <CancellationToken>()); Assert.Equal(type == BundleType.Batch ? AuditEventSubType.Batch : AuditEventSubType.Transaction, notification.FhirOperation); var results = notification.ApiCallResults; Assert.Equal(code200s, results["200"]); if (code404s > 0) { Assert.Equal(code404s, results["404"]); } else { Assert.Equal(1, results.Keys.Count); } }
public async Task GivenABundle_WhenOneRequestProducesA429_429IsRetriedThenSucceeds() { var bundle = new Hl7.Fhir.Model.Bundle { Type = BundleType.Batch, Entry = new List <EntryComponent> { new EntryComponent { Request = new RequestComponent { Method = HTTPVerb.GET, Url = "/Patient" } }, new EntryComponent { Request = new RequestComponent { Method = HTTPVerb.GET, Url = "/Patient" } }, new EntryComponent { Request = new RequestComponent { Method = HTTPVerb.GET, Url = "/Patient" } }, }, }; int callCount = 0; _router.When(r => r.RouteAsync(Arg.Any <RouteContext>())) .Do(info => { info.Arg <RouteContext>().Handler = context => { callCount++; if (callCount == 2) { context.Response.StatusCode = StatusCodes.Status429TooManyRequests; } else { context.Response.StatusCode = StatusCodes.Status200OK; } return(Task.CompletedTask); }; }); var bundleRequest = new BundleRequest(bundle.ToResourceElement()); BundleResponse bundleResponse = await _bundleHandler.Handle(bundleRequest, default); Assert.Equal(4, callCount); var bundleResource = bundleResponse.Bundle.ToPoco <Hl7.Fhir.Model.Bundle>(); Assert.Equal(3, bundleResource.Entry.Count); foreach (var entry in bundleResource.Entry) { Assert.Equal("200", entry.Response.Status); } }
public async Task GivenABundleWithAGet_WhenNotAuthorized_ReturnsABundleResponseWithCorrectEntry() { var bundle = new Hl7.Fhir.Model.Bundle { Type = Hl7.Fhir.Model.Bundle.BundleType.Batch, Entry = new List <Hl7.Fhir.Model.Bundle.EntryComponent> { new Hl7.Fhir.Model.Bundle.EntryComponent { Request = new Hl7.Fhir.Model.Bundle.RequestComponent { Method = Hl7.Fhir.Model.Bundle.HTTPVerb.GET, Url = "/Patient", }, }, }, }; _router.When(r => r.RouteAsync(Arg.Any <RouteContext>())) .Do(RouteAsyncFunction); var bundleRequest = new BundleRequest(bundle.ToResourceElement()); BundleResponse bundleResponse = await _bundleHandler.Handle(bundleRequest, CancellationToken.None); var bundleResource = bundleResponse.Bundle.ToPoco <Hl7.Fhir.Model.Bundle>(); Assert.Equal(Hl7.Fhir.Model.Bundle.BundleType.BatchResponse, bundleResource.Type); Assert.Single(bundleResource.Entry); Hl7.Fhir.Model.Bundle.EntryComponent entryComponent = bundleResource.Entry.First(); Assert.Equal("403", entryComponent.Response.Status); var operationOutcome = entryComponent.Response.Outcome as OperationOutcome; Assert.NotNull(operationOutcome); Assert.Single(operationOutcome.Issue); var issueComponent = operationOutcome.Issue.First(); Assert.Equal(OperationOutcome.IssueSeverity.Error, issueComponent.Severity); Assert.Equal(OperationOutcome.IssueType.Forbidden, issueComponent.Code); Assert.Equal("Authorization failed.", issueComponent.Diagnostics); void RouteAsyncFunction(CallInfo callInfo) { var routeContext = callInfo.Arg <RouteContext>(); routeContext.Handler = context => { context.Response.StatusCode = 403; return(Task.CompletedTask); }; } }
public async Task GivenABundle_WhenMultipleRequests_ReturnsABundleResponseWithCorrectOrder() { var bundle = new Hl7.Fhir.Model.Bundle { Type = Hl7.Fhir.Model.Bundle.BundleType.Batch, Entry = new List <Hl7.Fhir.Model.Bundle.EntryComponent> { new Hl7.Fhir.Model.Bundle.EntryComponent { Request = new RequestComponent { Method = HTTPVerb.GET, Url = "/Patient", }, }, new Hl7.Fhir.Model.Bundle.EntryComponent { Request = new RequestComponent { Method = HTTPVerb.POST, Url = "/Patient", }, Resource = new Hl7.Fhir.Model.Patient { }, }, new Hl7.Fhir.Model.Bundle.EntryComponent { Request = new RequestComponent { Method = HTTPVerb.PUT, Url = "/Patient/789", }, Resource = new Hl7.Fhir.Model.Patient { }, }, }, }; _router.When(r => r.RouteAsync(Arg.Any <RouteContext>())) .Do(RouteAsyncFunction); var bundleRequest = new BundleRequest(bundle.ToResourceElement()); BundleResponse bundleResponse = await _bundleHandler.Handle(bundleRequest, default); var bundleResource = bundleResponse.Bundle.ToPoco <Hl7.Fhir.Model.Bundle>(); Assert.Equal(Hl7.Fhir.Model.Bundle.BundleType.BatchResponse, bundleResource.Type); Assert.Equal(3, bundleResource.Entry.Count); Assert.Equal("403", bundleResource.Entry[0].Response.Status); Assert.Equal("404", bundleResource.Entry[1].Response.Status); Assert.Equal("200", bundleResource.Entry[2].Response.Status); }
public async Task GivenAnEmptyBatchBundle_WhenProcessed_ReturnsABundleResponseWithNoEntries() { var bundle = new Hl7.Fhir.Model.Bundle { Type = BundleType.Batch, }; var bundleRequest = new BundleRequest(bundle.ToResourceElement()); BundleResponse bundleResponse = await _bundleHandler.Handle(bundleRequest, CancellationToken.None); var bundleResource = bundleResponse.Bundle.ToPoco <Hl7.Fhir.Model.Bundle>(); Assert.Equal(BundleType.BatchResponse, bundleResource.Type); Assert.Empty(bundleResource.Entry); }
private async Task <BundleResponse> ExecuteTransactionForAllRequests(Hl7.Fhir.Model.Bundle responseBundle) { try { using (var transaction = _transactionHandler.BeginTransaction()) { await ExecuteAllRequests(responseBundle); transaction.Complete(); } } catch (TransactionAbortedException) { _logger.LogError("Failed to commit a transaction. Throwing BadRequest as a default exception."); throw new TransactionFailedException(Api.Resources.GeneralTransactionFailedError, HttpStatusCode.BadRequest); } return(new BundleResponse(responseBundle.ToResourceElement())); }
public async Task GivenABundle_WhenOneRequestProducesA429_SubsequentRequestAreSkipped() { var bundle = new Hl7.Fhir.Model.Bundle { Type = BundleType.Batch, Entry = new List <EntryComponent> { new EntryComponent { Request = new RequestComponent { Method = HTTPVerb.GET, Url = "/Patient" } }, new EntryComponent { Request = new RequestComponent { Method = HTTPVerb.GET, Url = "/Patient" } }, }, }; int callCount = 0; _router.When(r => r.RouteAsync(Arg.Any <RouteContext>())) .Do(info => { info.Arg <RouteContext>().Handler = context => { callCount++; context.Response.StatusCode = StatusCodes.Status429TooManyRequests; return(Task.CompletedTask); }; }); var bundleRequest = new BundleRequest(bundle.ToResourceElement()); BundleResponse bundleResponse = await _bundleHandler.Handle(bundleRequest, default); Assert.Equal(1, callCount); var bundleResource = bundleResponse.Bundle.ToPoco <Hl7.Fhir.Model.Bundle>(); Assert.Equal(2, bundleResource.Entry.Count); Assert.All(bundleResource.Entry, e => Assert.Equal("429", e.Response.Status)); }
public async Task <BundleResponse> Handle(BundleRequest bundleRequest, CancellationToken cancellationToken) { var bundleResource = bundleRequest.Bundle.ToPoco <Hl7.Fhir.Model.Bundle>(); if (bundleResource.Type != Hl7.Fhir.Model.Bundle.BundleType.Batch) { throw new MethodNotAllowedException(Microsoft.Health.Fhir.Api.Resources.OnlyCertainBundleTypesSupported); } await FillRequestLists(bundleResource.Entry); var responseBundle = new Hl7.Fhir.Model.Bundle { Type = Hl7.Fhir.Model.Bundle.BundleType.BatchResponse, }; await ExecuteAllRequests(responseBundle); return(new BundleResponse(responseBundle.ToResourceElement())); }
public async Task GivenABundle_WhenProcessed_CertainResponseHeadersArePropagatedToOuterResponse() { var bundle = new Hl7.Fhir.Model.Bundle { Type = BundleType.Batch, Entry = new List <EntryComponent> { new EntryComponent { Request = new RequestComponent { Method = HTTPVerb.GET, Url = "/Patient" } }, new EntryComponent { Request = new RequestComponent { Method = HTTPVerb.GET, Url = "/Patient" } }, }, }; string headerName = "x-ms-request-charge"; _router.When(r => r.RouteAsync(Arg.Any <RouteContext>())) .Do(info => { info.Arg <RouteContext>().Handler = context => { IHeaderDictionary headers = context.Response.Headers; headers.TryGetValue(headerName, out StringValues existing); headers[headerName] = (existing == default(StringValues) ? 2.0 : double.Parse(existing.ToString()) + 2.0).ToString(CultureInfo.InvariantCulture); return(Task.CompletedTask); }; }); var bundleRequest = new BundleRequest(bundle.ToResourceElement()); await _bundleHandler.Handle(bundleRequest, default); Assert.Equal("4", _fhirRequestContext.ResponseHeaders[headerName].ToString()); }
public async Task GivenABundleWithAnExportPost_WhenProcessed_ThenItIsProcessedCorrectly() { var bundle = new Hl7.Fhir.Model.Bundle { Type = BundleType.Batch, Entry = new List <EntryComponent> { new EntryComponent { Request = new RequestComponent { Method = HTTPVerb.POST, Url = "/$export" } }, }, }; var bundleRequest = new BundleRequest(bundle.ToResourceElement()); BundleResponse bundleResponse = await _bundleHandler.Handle(bundleRequest, CancellationToken.None); var bundleResource = bundleResponse.Bundle.ToPoco <Hl7.Fhir.Model.Bundle>(); Assert.Equal(BundleType.BatchResponse, bundleResource.Type); Assert.Single(bundleResource.Entry); }
public async Task GivenAFailedTransaction_WhenProcessed_ThenNoNotificationWillBeEmitted() { var bundle = new Hl7.Fhir.Model.Bundle { Type = BundleType.Transaction, Entry = new List <EntryComponent> { new EntryComponent { Request = new RequestComponent { Method = HTTPVerb.PUT, Url = "unused1", }, Resource = new Patient(), }, new EntryComponent { Request = new RequestComponent { // This will fail and cause an exception to be thrown Method = HTTPVerb.GET, Url = "unused2", }, }, }, }; _router.When(r => r.RouteAsync(Arg.Any <RouteContext>())) .Do(RouteAsyncFunction); var bundleRequest = new BundleRequest(bundle.ToResourceElement()); await Assert.ThrowsAsync <FhirTransactionFailedException>(() => _bundleHandler.Handle(bundleRequest, default)); await _mediator.DidNotReceive().Publish(Arg.Any <BundleMetricsNotification>(), Arg.Any <CancellationToken>()); }