public async Task When_ResourceDeleted_ApiResource_Returned_With_Then_Href_Populated() { // Arrange using var t = SystemTime.PauseForThread(); var executor = TestApiOperationExecutor .CreateStandalone(o => o .Http() .AddHateoasLinks() .AddResourceEvents <NullResourceEventRepository>() .WithOperation <ResourceSelfOperation>() .WithOperation <ResourceDeletionOperation>() .WithOperation <ResourceLinkWithoutIdOperation>() .WithOperation <ResourceLinkWithIdOperation>() ); // Act var result = await executor.ExecuteAsync(new ResourceDeletionOperation { Id = "87457", }); // Assert var okResult = result.ShouldBeOperationResultType <OkResult>(); var @event = okResult.Content.Should().BeOfType <ResourceDeleted <ResourceToReturn> >().Subject; @event.Created.UtcDateTime.Should().BeCloseTo(t.UtcNow); @event.Object.Should().Be("event"); @event.EventId.Should().Be("toReturn.deleted"); @event.ChangeType.Should().Be(ResourceEventChangeType.Deleted); @event.ResourceObject.Should().Be("toReturn"); @event.Href.Should().Be("https://api.blueprint-testing.com/api/resources/87457"); }
public void When_Single_Custom_Exception_Handler_Registered_Then_Compiles() { // Arrange var handler = new TestApiOperationHandler <TestApiCommand>(12345); // Act var middleware = new ExceptionHandlingRegisteringMiddleware( typeof(NotFoundException), (e) => { return(new Frame[] { LogFrame.Critical("Exception happened, oops"), new ReturnFrame(new Variable(typeof(object), "null")), }); }); var executor = TestApiOperationExecutor.CreateStandalone(o => o .WithHandler(handler) .Pipeline(p => p.AddMiddleware(middleware, MiddlewareStage.Execution))); // Assert var code = executor.WhatCodeDidIGenerateFor <TestApiCommand>(); code.Should().Contain("catch (Blueprint.Errors.NotFoundException"); code.Should().Contain("Exception happened, oops"); }
public async Task When_Executed_Then_Activity_Tags_Set() { // Arrange var expected = new SupportedTypesOperation { IntegerProperty = 761, EnumProperty = OperationEnum.EnumOne, GuidProperty = Guid.NewGuid(), StringProperty = "a string", NullableIntegerProperty = null, }; var handler = new TestApiOperationHandler <SupportedTypesOperation>(null); var executor = TestApiOperationExecutor.CreateStandalone(o => o.WithHandler(handler)); using var activity = Activity.Current = new Activity("PopulationTest").Start(); // Act await executor.ExecuteAsync(expected); // Assert var tags = activity.TagObjects.ToDictionary(k => k.Key, v => v.Value); tags.Should().Contain($"{nameof(SupportedTypesOperation)}.{nameof(expected.IntegerProperty)}", expected.IntegerProperty); tags.Should().Contain($"{nameof(SupportedTypesOperation)}.{nameof(expected.EnumProperty)}", expected.EnumProperty); tags.Should().Contain($"{nameof(SupportedTypesOperation)}.{nameof(expected.GuidProperty)}", expected.GuidProperty); tags.Should().Contain($"{nameof(SupportedTypesOperation)}.{nameof(expected.StringProperty)}", expected.StringProperty); // Nulls are ignored / removed tags.Should().NotContain($"{nameof(SupportedTypesOperation)}.{nameof(expected.NullableIntegerProperty)}", expected.NullableIntegerProperty); }
public async Task When_multiple_child_operations_finds_correct_one() { // Arrange var baseHandler = new TestApiOperationHandler <OperationBase>("ignored"); var child1Handler = new TestApiOperationHandler <OperationChild1>("ignored"); var child2Handler = new TestApiOperationHandler <OperationChild2>("ignored"); var executor = TestApiOperationExecutor .CreateStandalone(o => o .WithHandler(baseHandler) .WithHandler(child1Handler) .WithHandler(child2Handler) .WithOperation <OperationBase>(c => c.RequiresReturnValue = false) .WithOperation <OperationChild1>(c => c.RequiresReturnValue = false) .WithOperation <OperationChild2>(c => c.RequiresReturnValue = false)); // Act var result = await executor.ExecuteWithNewScopeAsync(new OperationChild2()); // Assert result.Should().BeOfType <NoResultOperationResult>(); baseHandler.WasCalled.Should().BeTrue(); child2Handler.WasCalled.Should().BeTrue(); child1Handler.WasCalled.Should().BeFalse(); }
public async Task When_Executed_Then_Sensitive_Properties_Excluded_From_Activity_Tags() { // Arrange var expected = new SensitiveOperation { NotSensitiveProperty = "NotSensitiveProperty", Password = "******", PasswordOne = "PasswordOne", ASensitiveProperty = "ASensitiveProperty", ADoNotAuditProperty = "ADoNotAuditProperty", }; var handler = new TestApiOperationHandler <SensitiveOperation>(null); var executor = TestApiOperationExecutor.CreateStandalone(o => o.WithHandler(handler)); using var activity = Activity.Current = new Activity("PopulationTest").Start(); // Act await executor.ExecuteAsync(expected); // Assert var tags = activity.TagObjects.ToDictionary(k => k.Key, v => v.Value); tags.Should().HaveCount(1); tags.Should().Contain($"{nameof(SensitiveOperation)}.{nameof(expected.NotSensitiveProperty)}", expected.NotSensitiveProperty); }
public async Task When_Dependency_From_Operation_Context_And_IoC_Then_Injects() { // Arrange var operation = new InlineHandle(); var executor = TestApiOperationExecutor.CreateStandalone( o => o .WithOperation <InlineHandle>() .AddAuthentication(a => a.UseContextLoader <AnonymousUserAuthorisationContextFactory>()) .AddAuthorisation(), s => { s.AddSingleton <IClaimsIdentityProvider, NullClaimsIdentityProvider>(); s.AddTransient <IDependency, Dependency>(); }); // Act await executor.ExecuteWithNewScopeAsync(operation); // Assert operation.Context.Should().NotBeNull(); operation.Context.Operation.Should().Be(operation); operation.Dependency.Should().NotBeNull(); operation.User.Should().NotBeNull(); }
public void When_Return_Is_Not_Compatible_With_Declared_Then_Exception_Thrown() { // Arrange Action create = () => TestApiOperationExecutor.CreateStandalone(o => o .WithOperation <WrongDeclaredReturnType>()); // Assert create.Should().ThrowExactly <InvalidReturnTypeException>(); }
private async Task ShouldCallInlineMethod <T>(Action <object> assertContent) where T : new() { // Arrange var executor = TestApiOperationExecutor.CreateStandalone(o => o.WithOperation <T>()); // Act var result = await executor.ExecuteWithNewScopeAsync(new T()); // Assert var okResult = result.ShouldBeOperationResultType <OkResult>(); assertContent(okResult.Content); }
public async Task When_Specific_Handler_Exists_Then_Finds_In_Scan() { // Arrange var executor = TestApiOperationExecutor.CreateStandalone(o => o.WithOperation <ScanOperation>()); // Act var result = await executor.ExecuteWithNewScopeAsync(new ScanOperation()); // Assert var okResult = result.ShouldBeOperationResultType <OkResult>(); okResult.Content.Should().Be("6789"); }
public async Task With_Object_Declared_And_OperationResult_Derived_Return_No_Wrapping() { // Arrange var executor = TestApiOperationExecutor.CreateStandalone(o => o.WithOperation <OperationAsRecord>()); var returnValue = new StatusCodeResult(HttpStatusCode.OK); // Act var result = await executor.ExecuteWithNewScopeAsync(new OperationAsRecord(returnValue)); // Assert result.Should().Be(returnValue); }
public async Task When_CancellationToken_not_cancelled_runs_to_completion() { // Arrange var cancellationToken = new CancellationTokenSource(); var executor = TestApiOperationExecutor.CreateStandalone(o => o.WithOperation <CancellableOperation>()); // Act var result = await executor.ExecuteWithNewScopeAsync(new CancellableOperation(), cancellationToken.Token); // Assert result.Should().BeOfType <NoResultOperationResult>(); }
public async Task When_Interface_Operation_Registered_RequiresReturnValue_False_Concrete_Operation_Can_Be_Executed() { // Arrange var executor = TestApiOperationExecutor .CreateStandalone(o => o .WithHandler(new TestApiOperationHandler <OperationImpl>("ignored")) .WithOperation <IOperationInterface>(c => c.RequiresReturnValue = false)); // Act var result = await executor.ExecuteWithNewScopeAsync(new OperationImpl()); // Assert result.Should().BeOfType <OkResult>(); }
public void When_Interface_Operation_Registered_RequiresReturnValue_True_Exception_On_Build() { // Arrange Action tryBuildExecutor = () => TestApiOperationExecutor .CreateStandalone(o => o .WithHandler(new TestApiOperationHandler <OperationImpl>("ignored")) .WithOperation <IOperationInterface>(c => c.RequiresReturnValue = true)); // Act tryBuildExecutor.Should().ThrowExactly <InvalidOperationException>() .WithMessage(@"Unable to build an executor for the operation Blueprint.Tests.Core.Given_PolymorphicOperationDeclaration+IOperationInterface because the single handler registered, IoC as Blueprint.Tests.TestApiOperationHandler`1[Blueprint.Tests.Core.Given_PolymorphicOperationDeclaration+OperationImpl], did not return a variable but the operation has RequiresReturnValue set to true. This can happen if an the only registered handler for an operation is one that is NOT of the same type (for example a handler IApiOperationHandler<ConcreteClass> for the operation IOperationInterface) where it cannot be guaranteed that the handler will be executed."); }
public async Task When_Blueprint_ApiException_Activity_Status_Set_Based_On_Http_Status_Code(int status, StatusCode expected) { // Arrange var handler = new TestApiOperationHandler <TestOperation>(new ApiException("Failed", "test_failure", "Test failure for " + status, status)); var executor = TestApiOperationExecutor.CreateStandalone(o => o.WithHandler(handler)); using var activity = Activity.Current = new Activity("ExceptionTest").Start(); // Act await executor.ExecuteWithNoUnwrapAsync(new TestOperation()); // Assert activity.GetStatus().StatusCode.Should().Be(expected); }
public async Task When_Unhandled_Exception_Activity_Status_Set_To_Error(Type exceptionType) { // Arrange var handler = new TestApiOperationHandler <TestOperation>((Exception)Activator.CreateInstance(exceptionType)); var executor = TestApiOperationExecutor.CreateStandalone(o => o.WithHandler(handler)); using var activity = Activity.Current = new Activity("ExceptionTest").Start(); // Act await executor.ExecuteWithNoUnwrapAsync(new TestOperation()); // Assert activity.GetStatus().StatusCode.Should().Be(StatusCode.Error); }
public async Task When_Operation_Does_Not_Pass_Validation_Then_Handler_Not_Executed() { // Arrange var handler = new TestApiOperationHandler <HasRequiredPropertyOperation>(12345); var executor = TestApiOperationExecutor.CreateStandalone(o => o.WithHandler(handler)); // Act await executor.ExecuteWithNewScopeAsync(new HasRequiredPropertyOperation { TheProperty = null }); // Assert handler.WasCalled.Should().BeFalse(); }
public async Task When_Returned_Object_Is_More_Specific_And_OperationResult_Does_Not_Convert() { // Arrange var okResult = new OkResult("theReturn"); var operation = new RuntimeSpecificReturnAsync(okResult); var executor = TestApiOperationExecutor.CreateStandalone(o => o.WithOperation <RuntimeSpecificReturnAsync>()); // Act var result = await executor.ExecuteWithNewScopeAsync(operation); // Assert var actualOkResult = result.ShouldBeOperationResultType <OkResult>(); actualOkResult.Should().BeSameAs(okResult); }
public async Task When_CancellationToken_cancelled_UnhandledExceptionOperationResult_returned() { // Arrange var cancellationToken = new CancellationTokenSource(); cancellationToken.Cancel(); var executor = TestApiOperationExecutor.CreateStandalone(o => o.WithOperation <CancellableOperation>()); // Act Func <Task> tryExecute = () => executor.ExecuteWithNewScopeAsync(new CancellableOperation(), cancellationToken.Token); // Assert await tryExecute.Should().ThrowExactlyAsync <OperationCanceledException>(); }
public async Task When_DataAnnotations_ValidationException_Thrown_Then_Activity_Status_OK() { // Arrange var expected = new TestOperation(); var handler = new TestApiOperationHandler <TestOperation>(new System.ComponentModel.DataAnnotations.ValidationException("Validation failed")); var executor = TestApiOperationExecutor.CreateStandalone(o => o.WithHandler(handler)); using var activity = Activity.Current = new Activity("ExceptionTest").Start(); // Act await executor.ExecuteWithNoUnwrapAsync(expected); // Assert activity.GetStatus().StatusCode.Should().Be(StatusCode.Ok); }
public async Task When_Blueprint_ValidationException_Thrown_Then_No_Exception_Recorded() { // Arrange var expected = new TestOperation(); var handler = new TestApiOperationHandler <TestOperation>(new Blueprint.Validation.ValidationException("Validation failed")); var executor = TestApiOperationExecutor.CreateStandalone(o => o.WithHandler(handler)); using var activity = Activity.Current = new Activity("ExceptionTest").Start(); // Act await executor.ExecuteWithNoUnwrapAsync(expected); // Assert activity.Events.Should().BeEmpty(); }
public void When_Scoped_Then_GetRequiredService_At_Runtime() { // Arrange var handler = new TestApiOperationHandler <OperationWithInjectable>(12345); // Act var executor = TestApiOperationExecutor.CreateStandalone(o => o .WithHandler(handler) .Pipeline(p => p.AddMiddlewareBefore <MiddlewareWithDependencyInjectionVariable <IInjectable> >(MiddlewareStage.Execution)), s => s.AddScoped(typeof(IInjectable), typeof(Injectable))); // Assert var code = executor.WhatCodeDidIGenerateFor <OperationWithInjectable>(); code.Should().Contain("context.ServiceProvider.GetRequiredService<Blueprint.Tests.IoC.Given_DependencyInjection_Container.IInjectable>();"); }
public async Task When_Unhandled_Exception_Activity_Exception_Recorded(Type exceptionType) { // Arrange var handler = new TestApiOperationHandler <TestOperation>((Exception)Activator.CreateInstance(exceptionType)); var executor = TestApiOperationExecutor.CreateStandalone(o => o.WithHandler(handler)); using var activity = Activity.Current = new Activity("ExceptionTest").Start(); // Act await executor.ExecuteWithNoUnwrapAsync(new TestOperation()); // Assert activity.Events.Should().Contain(e => e.Name == "exception" && e.Tags.Any(t => t.Key == "exception.type")); }
public async Task When_Empty_Operation_Then_Result_Executed() { // Arrange var toReturn = 12345; var handler = new TestApiOperationHandler <EmptyOperation>(toReturn); var executor = TestApiOperationExecutor.CreateStandalone(o => o.WithHandler(handler)); // Act var result = await executor.ExecuteWithNewScopeAsync(new EmptyOperation()); // Assert var okResult = result.ShouldBeOperationResultType <OkResult>(); okResult.Content.Should().Be(toReturn); handler.WasCalled.Should().BeTrue(); }
public async Task With_Object_Declared_And_NOT_OperationResult_Derived_Return_Wrapped() { // Arrange var executor = TestApiOperationExecutor.CreateStandalone(o => o.WithOperation <OperationWithObjectReturn>()); var returnValue = new object(); // Act var result = await executor.ExecuteWithNewScopeAsync(new OperationWithObjectReturn { Result = returnValue }); // Assert result.Should().BeOfType <OkResult>(); result.As <OkResult>().Content.Should().Be(returnValue); }
public async Task When_Dependency_From_Operation_Context_And_IoC_Then_Injects() { // Arrange var operation = new InlineHandle(); var executor = TestApiOperationExecutor.CreateStandalone( o => o.WithOperation <InlineHandle>(), s => s.AddTransient <IDependency, Dependency>()); // Act await executor.ExecuteWithNewScopeAsync(operation); // Assert operation.Context.Should().NotBeNull(); operation.Context.Operation.Should().Be(operation); operation.Dependency.Should().NotBeNull(); }
public async Task When_User_Does_Have_Required_Claim_Then_Exception() { // Arrange var executor = TestApiOperationExecutor.CreateStandalone(o => o .WithOperation <ClaimRequiredOperation>() .AddAuthentication(a => a.UseContextLoader <TestUserAuthorisationContextFactory>()) .AddAuthorisation()); // Act var result = await executor.ExecuteWithAuth( new ClaimRequiredOperation(), new Claim(ClaimTypes.Permission, "*", "ExecuteThisOperation")); // Assert var okResult = result.ShouldBeOperationResultType <OkResult>(); okResult.Content.Should().Be("12345"); }
public async Task When_User_Does_Not_Have_Required_Claim_Then_Exception() { // Arrange var executor = TestApiOperationExecutor.CreateStandalone(o => o .WithOperation <ClaimRequiredOperation>() .AddAuthentication(a => a.UseContextLoader <TestUserAuthorisationContextFactory>()) .AddAuthorisation()); // Act Func <Task> tryExecute = () => executor.ExecuteWithAuth(new ClaimRequiredOperation()); // Assert var forbiddenException = await tryExecute.Should().ThrowExactlyAsync <ForbiddenException>(); forbiddenException.And.Detail.Should().Be("User does not have required claim urn:claims/permission ExecuteThisOperation for *"); forbiddenException.And.Message.Should().Be("User does not have required claim urn:claims/permission ExecuteThisOperation for *"); forbiddenException.And.Title.Should().Be("You do not have enough permissions to perform this action"); }
public async Task When_Handler_Already_Registered_Then_Used() { // Arrange var handler = new TestApiOperationHandler <TestApiCommand>("1234"); var executor = TestApiOperationExecutor.CreateStandalone(o => o.WithHandler(handler)); // Act var result = await executor.ExecuteWithNewScopeAsync(new TestApiCommand { AStringProperty = "the string value", ASensitiveStringProperty = "the sensitive value" }); // Assert var okResult = result.ShouldBeOperationResultType <OkResult>(); okResult.Content.Should().Be("1234"); }
public async Task When_Generic_Operation_Type_Can_Compile() { // Arrange var handler = new TestApiOperationHandler <GenericOperation <TestApiCommand> >("12345"); var executor = TestApiOperationExecutor.CreateStandalone(o => o .WithHandler(handler) .AddLogging()); // Act var result = await executor.ExecuteWithNewScopeAsync(new GenericOperation <TestApiCommand> { Operation = new TestApiCommand(), }); // Assert result.Should().NotBeNull(); }
public async Task When_Middleware_Requests_Variable_Fulfilled_By_Open_Generic_DI_Registration() { // Arrange var toReturn = 12345; var handler = new TestApiOperationHandler <OperationWithInjectable>(toReturn); var executor = TestApiOperationExecutor.CreateStandalone( o => o .WithHandler(handler) .Pipeline(p => p.AddMiddlewareBefore <MiddlewareWithDependencyInjectionVariable <IOptions <MyOptions> > >(MiddlewareStage.Execution)), s => s.AddOptions <MyOptions>()); // Act await executor.ExecuteWithNewScopeAsync(new OperationWithInjectable()); // Assert handler.OperationPassed.InjectableProperty.Should().NotBeNull(); }