public void ShouldFailIfStackExists() { var logger = new TestLogger(this.output); var mockClientFactory = TestHelpers.GetClientFactoryMock(); var mockContext = TestHelpers.GetContextMock(logger); var mockCloudFormation = new Mock <IAmazonCloudFormation>(); mockCloudFormation.Setup(cf => cf.DescribeStacksAsync(It.IsAny <DescribeStacksRequest>(), default)).ReturnsAsync( new DescribeStacksResponse { Stacks = new List <Stack> { new Stack { StackName = StackName } } }); mockClientFactory.Setup(f => f.CreateCloudFormationClient()).Returns(mockCloudFormation.Object); var runner = CloudFormationRunner.Builder(mockContext.Object, StackName) .WithClientFactory(mockClientFactory.Object) .WithTemplateLocation(this.fixture.TestStackJsonTemplate.FullPath) .Build(); Func <Task <CloudFormationResult> > action = async() => await runner.CreateStackAsync(); action.Should().Throw <StackOperationException>().And.OperationalState.Should().Be(StackOperationalState.Exists); }
public async void ShouldCreateStackIfStackDoesNotExist() { var logger = new TestLogger(this.output); var mockClientFactory = TestHelpers.GetClientFactoryMock(); var mockContext = TestHelpers.GetContextMock(logger); var mockCloudFormation = new Mock <IAmazonCloudFormation>(); mockCloudFormation.SetupSequence(cf => cf.DescribeStacksAsync(It.IsAny <DescribeStacksRequest>(), default)) .Throws(new AmazonCloudFormationException($"Stack with id {StackName} does not exist")).ReturnsAsync( new DescribeStacksResponse { Stacks = new List <Stack> { new Stack() { StackName = StackName, StackId = StackId, StackStatus = StackStatus.CREATE_COMPLETE } } }); mockCloudFormation.Setup(cf => cf.CreateStackAsync(It.IsAny <CreateStackRequest>(), default)) .ReturnsAsync(new CreateStackResponse { StackId = StackId }); mockCloudFormation.Setup(cf => cf.DescribeStackEventsAsync(It.IsAny <DescribeStackEventsRequest>(), default)) .ReturnsAsync( new DescribeStackEventsResponse { StackEvents = new List <StackEvent> { new StackEvent { StackName = StackName, StackId = StackId, ResourceStatus = ResourceStatus.CREATE_COMPLETE, Timestamp = DateTime.Now.AddSeconds(1) } } }); mockCloudFormation.Setup(cf => cf.DescribeStackResourcesAsync(It.IsAny <DescribeStackResourcesRequest>(), default)) .ReturnsAsync(new DescribeStackResourcesResponse { StackResources = new List <StackResource>() }); mockClientFactory.Setup(f => f.CreateCloudFormationClient()).Returns(mockCloudFormation.Object); var runner = CloudFormationRunner.Builder(mockContext.Object, StackName) .WithClientFactory(mockClientFactory.Object) .WithFollowOperation() .WithTemplateLocation(this.fixture.TestStackJsonTemplate.FullPath) .Build(); (await runner.CreateStackAsync()).StackOperationResult.Should().Be(StackOperationResult.StackCreated); logger.StackEvents.Count.Should().BeGreaterThan(0); }
public async Task ShouldReturnStackUpdateInProgressIfWaitForInProgressUpdateNotSpecified() { var logger = new TestLogger(this.output); var mockClientFactory = TestHelpers.GetClientFactoryMock(); var mockContext = TestHelpers.GetContextMock(logger); var mockCloudFormation = new Mock <IAmazonCloudFormation>(); mockCloudFormation.SetupSequence(cf => cf.DescribeStacksAsync(It.IsAny <DescribeStacksRequest>(), default)) .ReturnsAsync(ResponseStackCreateComplete).ReturnsAsync(ResponseStackCreateComplete) .ReturnsAsync(ResponseStackCreateComplete); mockCloudFormation.Setup(cf => cf.CreateChangeSetAsync(It.IsAny <CreateChangeSetRequest>(), default)) .ReturnsAsync( new CreateChangeSetResponse { Id = "arn:aws:cloudformation:eu-west-1:123456789012:changeset/1234" }); mockCloudFormation .SetupSequence(cf => cf.DescribeChangeSetAsync(It.IsAny <DescribeChangeSetRequest>(), default)) .ReturnsAsync(new DescribeChangeSetResponse { Status = ChangeSetStatus.CREATE_IN_PROGRESS }) .ReturnsAsync( new DescribeChangeSetResponse { Status = ChangeSetStatus.CREATE_COMPLETE, Changes = StockChange }); mockCloudFormation .SetupSequence(cf => cf.DescribeStackEventsAsync(It.IsAny <DescribeStackEventsRequest>(), default)) .ReturnsAsync( new DescribeStackEventsResponse { StackEvents = new List <StackEvent> { new StackEvent { StackName = StackName, StackId = StackId, ResourceStatus = ResourceStatus.CREATE_COMPLETE, Timestamp = DateTime.Now.AddDays(-1) } } }); mockClientFactory.Setup(f => f.CreateCloudFormationClient()).Returns(mockCloudFormation.Object); var runner = CloudFormationRunner.Builder(mockContext.Object, StackName) .WithClientFactory(mockClientFactory.Object) .WithTemplateLocation(this.fixture.TestStackJsonTemplate.FullPath).Build(); (await runner.UpdateStackAsync(_ => true)).StackOperationResult.Should() .Be(StackOperationResult.StackUpdateInProgress); logger.ChangeSets.Count.Should().BeGreaterThan(0); logger.InfoMessages.Any(i => i.Contains($"Updating stack '{StackName}'")).Should().BeTrue(); }
public void ShouldThrowIfAnotherUpdateBeganWhileUserWasReviewingChangeset() { var logger = new TestLogger(this.output); var mockClientFactory = TestHelpers.GetClientFactoryMock(); var mockContext = TestHelpers.GetContextMock(logger); var mockCloudFormation = new Mock <IAmazonCloudFormation>(); mockCloudFormation.SetupSequence(cf => cf.DescribeStacksAsync(It.IsAny <DescribeStacksRequest>(), default)) .ReturnsAsync(ResponseStackCreateComplete).ReturnsAsync(ResponseStackCreateComplete).ReturnsAsync( new DescribeStacksResponse { Stacks = new List <Stack> { new Stack() { StackName = StackName, StackStatus = StackStatus.UPDATE_IN_PROGRESS, Parameters = new List <Parameter>() } } }); mockCloudFormation.Setup(cf => cf.CreateChangeSetAsync(It.IsAny <CreateChangeSetRequest>(), default)) .ReturnsAsync( new CreateChangeSetResponse { Id = "arn:aws:cloudformation:eu-west-1:123456789012:changeset/1234" }); mockCloudFormation .SetupSequence(cf => cf.DescribeChangeSetAsync(It.IsAny <DescribeChangeSetRequest>(), default)) .ReturnsAsync(new DescribeChangeSetResponse { Status = ChangeSetStatus.CREATE_IN_PROGRESS }) .ReturnsAsync( new DescribeChangeSetResponse { Status = ChangeSetStatus.CREATE_COMPLETE, Changes = StockChange }); mockClientFactory.Setup(f => f.CreateCloudFormationClient()).Returns(mockCloudFormation.Object); var runner = CloudFormationRunner.Builder(mockContext.Object, StackName) .WithClientFactory(mockClientFactory.Object) .WithTemplateLocation(this.fixture.TestStackJsonTemplate.FullPath).Build(); Func <Task <CloudFormationResult> > action = async() => await runner.UpdateStackAsync(_ => true); action.Should().Throw <StackOperationException>().WithMessage("Stack is being modified by another process."); logger.ChangeSets.Count.Should().BeGreaterThan(0); }
public async Task ShouldUploadToS3BeforeCreateChangesetIfForceS3IsSet() { var logger = new TestLogger(this.output); var mockClientFactory = TestHelpers.GetClientFactoryMock(); var mockContext = TestHelpers.GetContextMock(logger); var mockS3Util = TestHelpers.GetS3UtilMock(); var mockCloudFormation = new Mock <IAmazonCloudFormation>(); mockContext.Setup(ctx => ctx.S3Util).Returns(mockS3Util.Object); mockCloudFormation.SetupSequence(cf => cf.DescribeStacksAsync(It.IsAny <DescribeStacksRequest>(), default)) .ReturnsAsync(ResponseStackCreateComplete).ReturnsAsync(ResponseStackCreateComplete); mockCloudFormation.Setup(cf => cf.CreateChangeSetAsync(It.IsAny <CreateChangeSetRequest>(), default)) .ReturnsAsync( new CreateChangeSetResponse { Id = "arn:aws:cloudformation:eu-west-1:123456789012:changeset/1234" }); mockCloudFormation .SetupSequence(cf => cf.DescribeChangeSetAsync(It.IsAny <DescribeChangeSetRequest>(), default)) .ReturnsAsync(new DescribeChangeSetResponse { Status = ChangeSetStatus.CREATE_IN_PROGRESS }) .ReturnsAsync( new DescribeChangeSetResponse { Status = ChangeSetStatus.CREATE_COMPLETE, Changes = StockChange }); mockClientFactory.Setup(f => f.CreateCloudFormationClient()).Returns(mockCloudFormation.Object); var runner = CloudFormationRunner.Builder(mockContext.Object, StackName) .WithClientFactory(mockClientFactory.Object) .WithTemplateLocation(this.fixture.TestStackJsonTemplate.FullPath).WithChangesetOnly().WithForceS3() .Build(); (await runner.UpdateStackAsync(null)).StackOperationResult.Should().Be(StackOperationResult.NoChange); mockS3Util.Verify( s3 => s3.UploadOversizeArtifactToS3( It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <UploadFileType>()), Times.Exactly(1)); logger.InfoMessages.Last().Should().Be("Not updating stack since CreateChangesetOnly = true"); logger.ChangeSets.Count.Should().BeGreaterThan(0); }
public void ShouldFailIfStackBusyAndWaitIsFalse(string stackStatus) { var expectedMessage = "Stack is being modified by another process."; var logger = new TestLogger(this.output); var mockClientFactory = TestHelpers.GetClientFactoryMock(); var mockContext = TestHelpers.GetContextMock(logger); var mockCloudFormation = new Mock <IAmazonCloudFormation>(); mockCloudFormation.SetupSequence(cf => cf.DescribeStacksAsync(It.IsAny <DescribeStacksRequest>(), default)) .ReturnsAsync( new DescribeStacksResponse { Stacks = new List <Stack> { new Stack() { StackName = StackName, StackStatus = StackStatus.FindValue(stackStatus) } } }).ReturnsAsync( new DescribeStacksResponse { Stacks = new List <Stack> { new Stack() { StackName = StackName, StackStatus = StackStatus.FindValue(stackStatus) } } }); mockClientFactory.Setup(f => f.CreateCloudFormationClient()).Returns(mockCloudFormation.Object); var runner = CloudFormationRunner.Builder(mockContext.Object, StackName) .WithClientFactory(mockClientFactory.Object) .WithTemplateLocation(this.fixture.TestStackJsonTemplate.FullPath).Build(); Func <Task <CloudFormationResult> > action = async() => await runner.UpdateStackAsync(null); action.Should().Throw <StackOperationException>().WithMessage(expectedMessage); }
public void ShouldFailIfStackDoesNotExist() { var logger = new TestLogger(this.output); var mockClientFactory = TestHelpers.GetClientFactoryMock(); var mockContext = TestHelpers.GetContextMock(logger); var mockCloudFormation = new Mock <IAmazonCloudFormation>(); mockCloudFormation.Setup(cf => cf.DescribeStacksAsync(It.IsAny <DescribeStacksRequest>(), default)).Throws( new AmazonCloudFormationException($"Stack with id {StackName} does not exist")); mockClientFactory.Setup(f => f.CreateCloudFormationClient()).Returns(mockCloudFormation.Object); var runner = CloudFormationRunner.Builder(mockContext.Object, StackName) .WithClientFactory(mockClientFactory.Object) .WithTemplateLocation(this.fixture.TestStackJsonTemplate.FullPath).Build(); Func <Task <CloudFormationResult> > action = async() => await runner.UpdateStackAsync(null); action.Should().Throw <StackOperationException>().WithMessage("Stack does not exist."); }
public void ShouldFailIfStackIsBrokenOrBusy(string stackStatus, StackOperationalState expectedOutcome) { var logger = new TestLogger(this.output); var mockClientFactory = TestHelpers.GetClientFactoryMock(); var mockContext = TestHelpers.GetContextMock(logger); var mockCloudFormation = new Mock <IAmazonCloudFormation>(); mockCloudFormation.SetupSequence(cf => cf.DescribeStacksAsync(It.IsAny <DescribeStacksRequest>(), default)) .ReturnsAsync( new DescribeStacksResponse { Stacks = new List <Stack> { new Stack() { StackName = StackName, StackStatus = StackStatus.FindValue(stackStatus) } } }).ReturnsAsync( new DescribeStacksResponse { Stacks = new List <Stack> { new Stack() { StackName = StackName, StackStatus = StackStatus.FindValue(stackStatus) } } }); mockClientFactory.Setup(f => f.CreateCloudFormationClient()).Returns(mockCloudFormation.Object); var runner = CloudFormationRunner.Builder(mockContext.Object, StackName) .WithClientFactory(mockClientFactory.Object) .Build(); Func <Task <CloudFormationResult> > action = async() => await runner.DeleteStackAsync(); action.Should().Throw <StackOperationException>().And.OperationalState.Should().Be(expectedOutcome); }
public void ShouldFailIfStackDoesNotExist() { var logger = new TestLogger(this.output); var mockClientFactory = TestHelpers.GetClientFactoryMock(); var mockContext = TestHelpers.GetContextMock(logger); var mockCloudFormation = new Mock <IAmazonCloudFormation>(); mockCloudFormation.Setup(cf => cf.DescribeStacksAsync(It.IsAny <DescribeStacksRequest>(), default)).Throws( new AmazonCloudFormationException($"Stack with id {StackName} does not exist")); mockClientFactory.Setup(f => f.CreateCloudFormationClient()).Returns(mockCloudFormation.Object); var runner = CloudFormationRunner.Builder(mockContext.Object, StackName) .WithClientFactory(mockClientFactory.Object) .WithFollowOperation() .Build(); Func <Task <CloudFormationResult> > action = async() => await runner.DeleteStackAsync(); action.Should().Throw <StackOperationException>().And.OperationalState.Should().Be(StackOperationalState.NotFound); }
public async Task ShouldCreateChangesetAndNotUpdateStackIfChangesetOnlySpecified() { var logger = new TestLogger(this.output); var mockClientFactory = TestHelpers.GetClientFactoryMock(); var mockContext = TestHelpers.GetContextMock(logger); var mockCloudFormation = new Mock <IAmazonCloudFormation>(); mockCloudFormation.SetupSequence(cf => cf.DescribeStacksAsync(It.IsAny <DescribeStacksRequest>(), default)) .ReturnsAsync(ResponseStackCreateComplete).ReturnsAsync(ResponseStackCreateComplete); mockCloudFormation.Setup(cf => cf.CreateChangeSetAsync(It.IsAny <CreateChangeSetRequest>(), default)) .ReturnsAsync( new CreateChangeSetResponse { Id = "arn:aws:cloudformation:eu-west-1:123456789012:changeset/1234" }); mockCloudFormation .SetupSequence(cf => cf.DescribeChangeSetAsync(It.IsAny <DescribeChangeSetRequest>(), default)) .ReturnsAsync(new DescribeChangeSetResponse { Status = ChangeSetStatus.CREATE_IN_PROGRESS }) .ReturnsAsync( new DescribeChangeSetResponse { Status = ChangeSetStatus.CREATE_COMPLETE, Changes = StockChange }); mockClientFactory.Setup(f => f.CreateCloudFormationClient()).Returns(mockCloudFormation.Object); var runner = CloudFormationRunner.Builder(mockContext.Object, StackName) .WithClientFactory(mockClientFactory.Object) .WithTemplateLocation(this.fixture.TestStackJsonTemplate.FullPath).WithChangesetOnly().Build(); (await runner.UpdateStackAsync(null)).StackOperationResult.Should().Be(StackOperationResult.NoChange); logger.InfoMessages.Last().Should().Be("Not updating stack since CreateChangesetOnly = true"); logger.ChangeSets.Count.Should().BeGreaterThan(0); }
public async Task ShouldReturnNoChangeIfChangesetReportsNoChanges(string statusReason) { var logger = new TestLogger(this.output); var mockClientFactory = TestHelpers.GetClientFactoryMock(); var mockContext = TestHelpers.GetContextMock(logger); var mockCloudFormation = new Mock <IAmazonCloudFormation>(); mockCloudFormation.SetupSequence(cf => cf.DescribeStacksAsync(It.IsAny <DescribeStacksRequest>(), default)) .ReturnsAsync(ResponseStackCreateComplete).ReturnsAsync(ResponseStackCreateComplete); mockCloudFormation.Setup(cf => cf.CreateChangeSetAsync(It.IsAny <CreateChangeSetRequest>(), default)) .ReturnsAsync( new CreateChangeSetResponse { Id = "arn:aws:cloudformation:eu-west-1:123456789012:changeset/1234" }); mockCloudFormation .SetupSequence(cf => cf.DescribeChangeSetAsync(It.IsAny <DescribeChangeSetRequest>(), default)) .ReturnsAsync(new DescribeChangeSetResponse { Status = ChangeSetStatus.CREATE_IN_PROGRESS }) .ReturnsAsync( new DescribeChangeSetResponse { Status = ChangeSetStatus.FAILED, StatusReason = statusReason }); mockClientFactory.Setup(f => f.CreateCloudFormationClient()).Returns(mockCloudFormation.Object); var runner = CloudFormationRunner.Builder(mockContext.Object, StackName) .WithClientFactory(mockClientFactory.Object) .WithTemplateLocation(this.fixture.TestStackJsonTemplate.FullPath).Build(); (await runner.UpdateStackAsync(null)).StackOperationResult.Should().Be(StackOperationResult.NoChange); logger.ChangeSets.Count.Should().Be(0); }
public async void ShouldDeleteStackIfStackExistsAndIsInCorrectState(string status) { var logger = new TestLogger(this.output); var mockClientFactory = TestHelpers.GetClientFactoryMock(); var mockContext = TestHelpers.GetContextMock(logger); var mockCloudFormation = new Mock <IAmazonCloudFormation>(); mockCloudFormation.SetupSequence(cf => cf.DescribeStacksAsync(It.IsAny <DescribeStacksRequest>(), default)) .ReturnsAsync( new DescribeStacksResponse { Stacks = new List <Stack> { new Stack() { StackName = StackName, StackStatus = StackStatus.FindValue(status) } } }).ReturnsAsync( new DescribeStacksResponse { Stacks = new List <Stack> { new Stack() { StackName = StackName, StackStatus = StackStatus.FindValue(status) } } }).ReturnsAsync( new DescribeStacksResponse { Stacks = new List <Stack> { new Stack() { StackName = StackName, StackStatus = StackStatus.DELETE_IN_PROGRESS } } }).ReturnsAsync( new DescribeStacksResponse { Stacks = new List <Stack> { new Stack() { StackName = StackName, StackStatus = StackStatus.DELETE_COMPLETE } } }); mockCloudFormation.Setup(cf => cf.DeleteStackAsync(It.IsAny <DeleteStackRequest>(), default)) .ReturnsAsync(new DeleteStackResponse()); mockCloudFormation.SetupSequence(cf => cf.DescribeStackEventsAsync(It.IsAny <DescribeStackEventsRequest>(), default)) .ReturnsAsync( new DescribeStackEventsResponse { StackEvents = new List <StackEvent> { new StackEvent { StackName = StackName, StackId = StackId, ResourceStatus = status, Timestamp = DateTime.Now.AddDays(-1) } } }) .ReturnsAsync( new DescribeStackEventsResponse { StackEvents = new List <StackEvent> { new StackEvent { StackName = StackName, StackId = StackId, ResourceStatus = ResourceStatus.DELETE_COMPLETE, Timestamp = DateTime.Now.AddSeconds(1) } } }) .ReturnsAsync( new DescribeStackEventsResponse { StackEvents = new List <StackEvent>() }); mockCloudFormation.Setup(cf => cf.DescribeStackResourcesAsync(It.IsAny <DescribeStackResourcesRequest>(), default)) .ReturnsAsync(new DescribeStackResourcesResponse { StackResources = new List <StackResource>() }); mockCloudFormation.Setup(cf => cf.GetTemplateAsync(It.IsAny <GetTemplateRequest>(), default)).ReturnsAsync( new GetTemplateResponse { TemplateBody = this.fixture.TestStackJsonString }); mockCloudFormation.Setup(cf => cf.GetTemplateSummaryAsync(It.IsAny <GetTemplateSummaryRequest>(), default)) .ReturnsAsync(new GetTemplateSummaryResponse { Parameters = new List <ParameterDeclaration>() }); mockClientFactory.Setup(f => f.CreateCloudFormationClient()).Returns(mockCloudFormation.Object); var runner = CloudFormationRunner.Builder(mockContext.Object, StackName) .WithClientFactory(mockClientFactory.Object) .WithFollowOperation() .Build(); (await runner.DeleteStackAsync()).StackOperationResult.Should().Be(StackOperationResult.StackDeleted); logger.StackEvents.Count.Should().BeGreaterThan(0); }
/// <summary> /// Gets the builder for <see cref="CloudFormationRunner"/> and populates the fields pertinent to this level. /// </summary> /// <returns>Builder for <see cref="CloudFormationRunner"/>.</returns> protected virtual CloudFormationBuilder GetBuilder() { return(CloudFormationRunner.Builder(this.CreateCloudFormationContext(), this.StackName) .WithClientToken(this.ClientRequestToken).WithRoleArn(this.RoleARN) .WithFollowOperation(!this.PassThru)); }
public void ShouldThrowIfUpdateFails(string finalState) { var logger = new TestLogger(this.output); var mockClientFactory = TestHelpers.GetClientFactoryMock(); var mockContext = TestHelpers.GetContextMock(logger); var mockCloudFormation = new Mock <IAmazonCloudFormation>(); mockCloudFormation.SetupSequence(cf => cf.DescribeStacksAsync(It.IsAny <DescribeStacksRequest>(), default)) .ReturnsAsync(ResponseStackCreateComplete).ReturnsAsync(ResponseStackCreateComplete) .ReturnsAsync(ResponseStackCreateComplete) .ReturnsAsync( new DescribeStacksResponse { Stacks = new List <Stack> { new Stack() { StackName = StackName, StackStatus = StackStatus.UPDATE_IN_PROGRESS, Parameters = new List <Parameter>() } } }).ReturnsAsync( new DescribeStacksResponse { Stacks = new List <Stack> { new Stack() { StackName = StackName, StackStatus = StackStatus.FindValue(finalState), Parameters = new List <Parameter>() } } }); mockCloudFormation .SetupSequence(cf => cf.DescribeStackEventsAsync(It.IsAny <DescribeStackEventsRequest>(), default)) .ReturnsAsync( new DescribeStackEventsResponse { StackEvents = new List <StackEvent> { new StackEvent { StackName = StackName, StackId = StackId, ResourceStatus = ResourceStatus.CREATE_COMPLETE, Timestamp = DateTime.Now.AddDays(-1) } } }).ReturnsAsync( new DescribeStackEventsResponse { StackEvents = new List <StackEvent> { new StackEvent { Timestamp = DateTime.Now.AddSeconds(1) } } }).ReturnsAsync( new DescribeStackEventsResponse { StackEvents = new List <StackEvent> { new StackEvent { Timestamp = DateTime.Now.AddSeconds(2) } } }).ReturnsAsync(new DescribeStackEventsResponse { StackEvents = new List <StackEvent>() }); mockCloudFormation.Setup(cf => cf.CreateChangeSetAsync(It.IsAny <CreateChangeSetRequest>(), default)) .ReturnsAsync( new CreateChangeSetResponse { Id = "arn:aws:cloudformation:eu-west-1:123456789012:changeset/1234" }); mockCloudFormation .SetupSequence(cf => cf.DescribeChangeSetAsync(It.IsAny <DescribeChangeSetRequest>(), default)) .ReturnsAsync(new DescribeChangeSetResponse { Status = ChangeSetStatus.CREATE_IN_PROGRESS }) .ReturnsAsync( new DescribeChangeSetResponse { Status = ChangeSetStatus.CREATE_COMPLETE, Changes = StockChange }); mockCloudFormation .Setup(cf => cf.DescribeStackResourcesAsync(It.IsAny <DescribeStackResourcesRequest>(), default)) .ReturnsAsync(new DescribeStackResourcesResponse { StackResources = new List <StackResource>() }); mockClientFactory.Setup(f => f.CreateCloudFormationClient()).Returns(mockCloudFormation.Object); var runner = CloudFormationRunner.Builder(mockContext.Object, StackName) .WithClientFactory(mockClientFactory.Object) .WithTemplateLocation(this.fixture.TestStackJsonTemplate.FullPath).WithFollowOperation().Build(); Func <Task <CloudFormationResult> > action = async() => await runner.UpdateStackAsync(_ => true); action.Should().Throw <StackOperationException>() .WithMessage($"Stack '{StackName}': Operation failed. Status is {finalState}"); logger.ChangeSets.Count.Should().BeGreaterThan(0); logger.InfoMessages.Any(i => i.Contains($"Updating stack '{StackName}'")).Should().BeTrue(); logger.StackEvents.Count.Should().BeGreaterThan(0); }