public async Task ProcessAsync_WorkerIsNull_Throws()
        {
            // arrange
            var mockedHttpRequestData = new MockedHttpRequestData(new MockedFunctionContext());

            // act, assert
            await Assert.ThrowsAsync <ArgumentNullException>(() =>
                                                             mockedHttpRequestData.HttpRequestData.ProcessAsync(null !)).ConfigureAwait(false);
        }
        public async Task ProcessAsync_WorkerFinishesSuccessfully_ReturnsResponseFromWorker()
        {
            // arrange
            var          request      = new MockedHttpRequestData(new MockedFunctionContext()).HttpRequestData;
            const string responseData = "Some data";

            // act
            var actual = await request.ProcessAsync(() => Task.FromResult(request.CreateResponse(
                                                                              new MemoryStream(Encoding.UTF8.GetBytes(responseData)), MediaTypeNames.Application.Xml))).ConfigureAwait(false);

            var actualResponseMessage = Encoding.UTF8.GetString(((MemoryStream)actual.Body).ToArray());

            // assert
            Assert.Equal(HttpStatusCode.OK, actual.StatusCode);
            Assert.Equal(responseData, actualResponseMessage);
        }
        public async Task AsHttpResponseData_ContentTypeIsJson_ReturnsResponseSerializedAsJson()
        {
            // arrange
            const string expectedXml = "{\"error\":{\"code\":\"VALIDATION_EXCEPTION\",\"message\":\"BundleIdAlreadyInUse\"}}";
            var          request     = new MockedHttpRequestData(new MockedFunctionContext());

            request.HttpRequestDataMock.Setup(x => x.Headers).Returns(new Microsoft.Azure.Functions.Worker.Http.HttpHeadersCollection(
                                                                          new[] { new KeyValuePair <string, IEnumerable <string> >(HeaderNames.ContentType, new[] { MediaTypeNames.Application.Json }) }));
            const string validationErrorMessage = nameof(BundleCreatedResponse.BundleIdAlreadyInUse);
            var          exception = new System.ComponentModel.DataAnnotations.ValidationException(validationErrorMessage);

            // act
            var actual = await exception.AsHttpResponseDataAsync(request.HttpRequestData).ConfigureAwait(false);

            var content = Encoding.UTF8.GetString(((MemoryStream)actual.Body).ToArray());

            // assert
            Assert.Equal(expectedXml, content);
        }
        public void CreateResponse_ValidStream_ReturnsResponse()
        {
            // arrange
            using var stream = new MemoryStream();
            var request  = new MockedHttpRequestData(new MockedFunctionContext());
            var response = request.HttpResponseDataMock;

            request.HttpRequestDataMock
            .Setup(x => x.CreateResponse())
            .Returns(response.Object);

            // act
            request.HttpRequestData.CreateResponse(stream, MediaTypeNames.Application.Xml);

            // assert
            // ReSharper disable once AccessToDisposedClosure
            response.VerifySet(x => x.Body       = stream, Times.Once());
            response.VerifySet(x => x.StatusCode = HttpStatusCode.OK, Times.Once());
        }
        public async Task ProcessAsync_WorkerThrowsValidationException_ReturnsBadRequestWithValidationErrorMessage()
        {
            // arrange
            var          request = new MockedHttpRequestData(new MockedFunctionContext()).HttpRequestData;
            const string validationErrorMessage = "Something is not right";

            // act
            var actual = await request.ProcessAsync(async() =>
            {
                await Task.FromException(new ValidationException(string.Empty, new[] { new ValidationFailure("propertyName", validationErrorMessage) })).ConfigureAwait(false);
                return(request.CreateResponse(HttpStatusCode.OK));
            }).ConfigureAwait(false);

            var actualResponseMessage = Encoding.UTF8.GetString(((MemoryStream)actual.Body).ToArray());

            // assert
            Assert.Equal(HttpStatusCode.BadRequest, actual.StatusCode);
            Assert.Contains(validationErrorMessage, actualResponseMessage, StringComparison.OrdinalIgnoreCase);
        }
        public async Task ProcessAsync_WorkerThrows_ReturnsInternalServerError()
        {
            // arrange
            var          request = new MockedHttpRequestData(new MockedFunctionContext()).HttpRequestData;
            const string internalServerErrorMessage = "Something's not right";

            // act
            var actual = await request.ProcessAsync(async() =>
            {
                await Task.FromException(new InvalidOperationException(internalServerErrorMessage)).ConfigureAwait(false);
                return(request.CreateResponse(HttpStatusCode.OK));
            }).ConfigureAwait(false);

            var actualResponseMessage = Encoding.UTF8.GetString(((MemoryStream)actual.Body).ToArray());

            // assert
            Assert.Equal(HttpStatusCode.InternalServerError, actual.StatusCode);
            Assert.NotEmpty(actualResponseMessage);
            Assert.DoesNotContain(internalServerErrorMessage, actualResponseMessage, StringComparison.OrdinalIgnoreCase);
        }
        public async Task AsHttpResponseData_ExceptionIsValidationException_ReturnsResponseWithAllErrorsAndStatusBadRequest()
        {
            // arrange
            var request = new MockedHttpRequestData(new MockedFunctionContext());
            var errors  = new[]
            {
                new ValidationFailure("prop1", "err1")
                {
                    ErrorCode = "code1"
                },
                new ValidationFailure("prop2", "err2")
                {
                    ErrorCode = "code2"
                }
            };
            var exception = new ValidationException(errors);

            // act
            var actual = await exception.AsHttpResponseDataAsync(request.HttpRequestData).ConfigureAwait(false);

            var actualFunctionError = JsonSerializer.Deserialize <ErrorResponse>(
                ((MemoryStream)actual.Body).ToArray(),
                new JsonSerializerOptions {
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase
            }) !;

            // assert
            var detailErrors = actualFunctionError.Error.Details !.ToArray();

            Assert.Equal(HttpStatusCode.BadRequest, actual.StatusCode);
            Assert.Equal(2, detailErrors.Length);
            for (var i = 0; i < detailErrors.Length; i++)
            {
                var expectedError = errors[i];
                var detail        = detailErrors[i];
                Assert.Equal(expectedError.ErrorCode, detail.Code);
                Assert.Equal(expectedError.ErrorMessage, detail.Message);
                Assert.Equal(expectedError.PropertyName, detail.Target);
            }
        }
        public async Task AsHttpResponseData_ExceptionIsDataAnnotationException_ReturnsResponseWithGenericErrorAndStatusValidationError()
        {
            // arrange
            var          request = new MockedHttpRequestData(new MockedFunctionContext());
            const string validationErrorMessage = nameof(BundleCreatedResponse.BundleIdAlreadyInUse);
            var          exception = new System.ComponentModel.DataAnnotations.ValidationException(validationErrorMessage);

            // act
            var actual = await exception.AsHttpResponseDataAsync(request.HttpRequestData).ConfigureAwait(false);

            var actualFunctionError = JsonSerializer.Deserialize <ErrorResponse>(
                ((MemoryStream)actual.Body).ToArray(),
                new JsonSerializerOptions {
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase
            }) !;
            var error = actualFunctionError.Error;

            // assert
            Assert.Equal(HttpStatusCode.BadRequest, actual.StatusCode);
            Assert.Equal("VALIDATION_EXCEPTION", error.Code);
            Assert.Equal(nameof(BundleCreatedResponse.BundleIdAlreadyInUse), error.Message);
            Assert.Null(error.Target);
            Assert.Null(error.Details);
        }
        public async Task AsHttpResponseData_ExceptionIsAnUnexpectedException_ReturnsResponseWithGenericErrorAndStatusInternalServerError()
        {
            // arrange
            var          request = new MockedHttpRequestData(new MockedFunctionContext());
            const string internalErrorMessage = "Something is not right";
            var          exception            = new ArgumentNullException(internalErrorMessage);

            // act
            var actual = await exception.AsHttpResponseDataAsync(request.HttpRequestData).ConfigureAwait(false);

            var actualFunctionError = JsonSerializer.Deserialize <ErrorResponse>(
                ((MemoryStream)actual.Body).ToArray(),
                new JsonSerializerOptions {
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase
            }) !;
            var error = actualFunctionError.Error;

            // assert
            Assert.Equal(HttpStatusCode.InternalServerError, actual.StatusCode);
            Assert.Equal("INTERNAL_ERROR", error.Code);
            Assert.Equal("An error occured while processing the request.", error.Message);
            Assert.Null(error.Target);
            Assert.Null(error.Details);
        }