private async Task PutPrepareToSendNotificationEventAsync( PrepareToSendNotificationOutcome prepareToSendNotificationOutcome, GetAudienceResult getAudienceResult, GetDeliveryChannelConfigsResult getDeliveryChannelConfigsResult, PrepareToSendNotificationResult prepareToSendNotificationResult, long trackingCodeId, IReadOnlyCollection <NamedValue <string> > inheritableTags) { PrepareToSendNotificationEventBase @event; switch (prepareToSendNotificationOutcome) { case PrepareToSendNotificationOutcome.AudienceOptedOutOfAllChannels: @event = new AudienceOptedOutOfAllChannelsEvent(trackingCodeId, DateTime.UtcNow, getAudienceResult, getDeliveryChannelConfigsResult, prepareToSendNotificationResult); break; case PrepareToSendNotificationOutcome.PreparedToSendOnAllChannels: @event = new PreparedToSendOnAllChannelsEvent(trackingCodeId, DateTime.UtcNow, getAudienceResult, getDeliveryChannelConfigsResult, prepareToSendNotificationResult); break; case PrepareToSendNotificationOutcome.PreparedToSendOnSomeChannels: @event = new PreparedToSendOnSomeChannelsEvent(trackingCodeId, DateTime.UtcNow, getAudienceResult, getDeliveryChannelConfigsResult, prepareToSendNotificationResult); break; case PrepareToSendNotificationOutcome.CouldNotPrepareToSendOnAnyChannelDespiteAttemptingAll: case PrepareToSendNotificationOutcome.CouldNotPrepareToSendOnAnyChannelBecauseOneForcedAllToBeDiscarded: @event = new CouldNotPrepareToSendOnAnyChannelEvent(trackingCodeId, DateTime.UtcNow, getAudienceResult, getDeliveryChannelConfigsResult, prepareToSendNotificationResult); break; default: throw new NotSupportedException(Invariant($"This {nameof(PrepareToSendNotificationOutcome)} is not supported: {prepareToSendNotificationOutcome}")); } var tags = this.buildPrepareToSendNotificationEventTagsProtocol.ExecuteBuildTags(trackingCodeId, @event, inheritableTags); await this.eventStream.PutWithIdAsync(trackingCodeId, @event, tags, ExistingRecordStrategy.DoNotWriteIfFoundByIdAndType); }
static PrepareToSendNotificationResultTest() { ConstructorArgumentValidationTestScenarios .RemoveAllScenarios() .AddScenario(() => new ConstructorArgumentValidationTestScenario <PrepareToSendNotificationResult> { Name = "constructor should throw ArgumentNullException when parameter 'channelToPrepareToSendOnChannelResultMap' is null scenario", ConstructionFunc = () => { var referenceObject = A.Dummy <PrepareToSendNotificationResult>(); var result = new PrepareToSendNotificationResult( null, referenceObject.CannotPrepareToSendOnChannelAction, referenceObject.ChannelsToSendOn); return(result); }, ExpectedExceptionType = typeof(ArgumentNullException), ExpectedExceptionMessageContains = new[] { "channelToPrepareToSendOnChannelResultMap", }, }) .AddScenario(() => new ConstructorArgumentValidationTestScenario <PrepareToSendNotificationResult> { Name = "constructor should throw ArgumentException when parameter 'channelToPrepareToSendOnChannelResultMap' contains a key-value pair with a null value scenario", ConstructionFunc = () => { var referenceObject = A.Dummy <PrepareToSendNotificationResult>().Whose(_ => _.ChannelToPrepareToSendOnChannelResultMap.Any()); var dictionaryWithNullValue = referenceObject.ChannelToPrepareToSendOnChannelResultMap.ToDictionary(_ => _.Key, _ => _.Value); var randomKey = dictionaryWithNullValue.Keys.ElementAt(ThreadSafeRandom.Next(0, dictionaryWithNullValue.Count)); dictionaryWithNullValue[randomKey] = null; var result = new PrepareToSendNotificationResult( dictionaryWithNullValue, referenceObject.CannotPrepareToSendOnChannelAction, referenceObject.ChannelsToSendOn); return(result); }, ExpectedExceptionType = typeof(ArgumentException), ExpectedExceptionMessageContains = new[] { "channelToPrepareToSendOnChannelResultMap", "contains at least one key-value pair with a null value", }, }) .AddScenario(() => new ConstructorArgumentValidationTestScenario <PrepareToSendNotificationResult> { Name = "constructor should throw ArgumentException when parameter 'channelToPrepareToSendOnChannelResultMap' values are not distinct", ConstructionFunc = () => { var referenceObject = A.Dummy <PrepareToSendNotificationResult>(); var prepareToSendOnChannelResult = A.Dummy <PrepareToSendOnChannelResult>(); var channelToPrepareToSendOnChannelResultMap = new Dictionary <IDeliveryChannel, PrepareToSendOnChannelResult> { { new SlackDeliveryChannel(), prepareToSendOnChannelResult }, { new EmailDeliveryChannel(), prepareToSendOnChannelResult }, }; var result = new PrepareToSendNotificationResult( channelToPrepareToSendOnChannelResultMap, referenceObject.CannotPrepareToSendOnChannelAction, null); return(result); }, ExpectedExceptionType = typeof(ArgumentException), ExpectedExceptionMessageContains = new[] { "prepareToSendOnChannelResult", "contains two or more elements that are equal" }, }) .AddScenario(() => new ConstructorArgumentValidationTestScenario <PrepareToSendNotificationResult> { Name = "constructor should throw ArgumentOutOfRangeException when parameter 'cannotPrepareToSendOnChannelAction' is CannotPrepareToSendOnChannelAction.Unknown.", ConstructionFunc = () => { var referenceObject = A.Dummy <PrepareToSendNotificationResult>(); var result = new PrepareToSendNotificationResult( referenceObject.ChannelToPrepareToSendOnChannelResultMap, CannotPrepareToSendOnChannelAction.Unknown, referenceObject.ChannelsToSendOn); return(result); }, ExpectedExceptionType = typeof(ArgumentOutOfRangeException), ExpectedExceptionMessageContains = new[] { "cannotPrepareToSendOnChannelAction", "Unknown" }, }) .AddScenario(() => new ConstructorArgumentValidationTestScenario <PrepareToSendNotificationResult> { Name = "constructor should throw ArgumentNullException when parameter 'channelsToSendOn' is null scenario", ConstructionFunc = () => { var referenceObject = A.Dummy <PrepareToSendNotificationResult>(); var result = new PrepareToSendNotificationResult( referenceObject.ChannelToPrepareToSendOnChannelResultMap, referenceObject.CannotPrepareToSendOnChannelAction, null); return(result); }, ExpectedExceptionType = typeof(ArgumentNullException), ExpectedExceptionMessageContains = new[] { "channelsToSendOn", }, }) .AddScenario(() => new ConstructorArgumentValidationTestScenario <PrepareToSendNotificationResult> { Name = "constructor should throw ArgumentException when parameter 'channelsToSendOn' contains a null element scenario", ConstructionFunc = () => { var referenceObject = A.Dummy <PrepareToSendNotificationResult>(); var result = new PrepareToSendNotificationResult( referenceObject.ChannelToPrepareToSendOnChannelResultMap, referenceObject.CannotPrepareToSendOnChannelAction, new IDeliveryChannel[0].Concat(referenceObject.ChannelsToSendOn).Concat(new IDeliveryChannel[] { null }).Concat(referenceObject.ChannelsToSendOn).ToList()); return(result); }, ExpectedExceptionType = typeof(ArgumentException), ExpectedExceptionMessageContains = new[] { "channelsToSendOn", "contains at least one null element", }, }) .AddScenario(() => new ConstructorArgumentValidationTestScenario <PrepareToSendNotificationResult> { Name = "constructor should throw ArgumentException when parameter 'channelsToSendOn' has a channel that's not a key in 'channelToPrepareToSendOnChannelResultMap'", ConstructionFunc = () => { var referenceObject = A.Dummy <PrepareToSendNotificationResult>(); var result = new PrepareToSendNotificationResult( new Dictionary <IDeliveryChannel, PrepareToSendOnChannelResult> { { new SlackDeliveryChannel(), A.Dummy <PrepareToSendOnChannelResult>() }, }, referenceObject.CannotPrepareToSendOnChannelAction, new[] { new EmailDeliveryChannel() }); return(result); }, ExpectedExceptionType = typeof(ArgumentException), ExpectedExceptionMessageContains = new[] { "channelToPrepareToSendOnChannelResultMap", "does not contain the key to search for", }, }); DeepCloneWithTestScenarios .RemoveAllScenarios() .AddScenario(() => new DeepCloneWithTestScenario <PrepareToSendNotificationResult> { Name = "DeepCloneWithChannelToPrepareToSendOnChannelResultMap should deep clone object and replace ChannelToPrepareToSendOnChannelResultMap with the provided channelToPrepareToSendOnChannelResultMap", WithPropertyName = "ChannelToPrepareToSendOnChannelResultMap", SystemUnderTestDeepCloneWithValueFunc = () => { var systemUnderTest = A.Dummy <PrepareToSendNotificationResult>(); var referenceObject = A.Dummy <PrepareToSendNotificationResult>().ThatIs(_ => (!systemUnderTest.ChannelToPrepareToSendOnChannelResultMap.IsEqualTo(_.ChannelToPrepareToSendOnChannelResultMap)) && systemUnderTest.ChannelsToSendOn.IsEqualTo(_.ChannelsToSendOn)); var result = new SystemUnderTestDeepCloneWithValue <PrepareToSendNotificationResult> { SystemUnderTest = systemUnderTest, DeepCloneWithValue = referenceObject.ChannelToPrepareToSendOnChannelResultMap, }; return(result); }, }) .AddScenario(() => new DeepCloneWithTestScenario <PrepareToSendNotificationResult> { Name = "DeepCloneWithCannotPrepareToSendOnChannelAction should deep clone object and replace CannotPrepareToSendOnChannelAction with the provided cannotPrepareToSendOnChannelAction", WithPropertyName = "CannotPrepareToSendOnChannelAction", SystemUnderTestDeepCloneWithValueFunc = () => { var systemUnderTest = A.Dummy <PrepareToSendNotificationResult>(); var referenceObject = A.Dummy <PrepareToSendNotificationResult>().ThatIs(_ => !systemUnderTest.CannotPrepareToSendOnChannelAction.IsEqualTo(_.CannotPrepareToSendOnChannelAction)); var result = new SystemUnderTestDeepCloneWithValue <PrepareToSendNotificationResult> { SystemUnderTest = systemUnderTest, DeepCloneWithValue = referenceObject.CannotPrepareToSendOnChannelAction, }; return(result); }, }) .AddScenario(() => new DeepCloneWithTestScenario <PrepareToSendNotificationResult> { Name = "DeepCloneWithChannelsToSendOn should deep clone object and replace ChannelsToSendOn with the provided channelsToSendOn", WithPropertyName = "ChannelsToSendOn", SystemUnderTestDeepCloneWithValueFunc = () => { var systemUnderTest = A.Dummy <PrepareToSendNotificationResult>().Whose(_ => _.ChannelToPrepareToSendOnChannelResultMap.Any()); var referenceObject = A.Dummy <PrepareToSendNotificationResult>().ThatIs(_ => (!systemUnderTest.ChannelsToSendOn.IsEqualTo(_.ChannelsToSendOn)) && _.ChannelsToSendOn.All(c => systemUnderTest.ChannelToPrepareToSendOnChannelResultMap.ContainsKey(c))); var result = new SystemUnderTestDeepCloneWithValue <PrepareToSendNotificationResult> { SystemUnderTest = systemUnderTest, DeepCloneWithValue = referenceObject.ChannelsToSendOn, }; return(result); }, }); var referenceObjectForEquatableTestScenarios = A.Dummy <PrepareToSendNotificationResult>().Whose(_ => _.ChannelToPrepareToSendOnChannelResultMap.Any()); EquatableTestScenarios .RemoveAllScenarios() .AddScenario(() => new EquatableTestScenario <PrepareToSendNotificationResult> { Name = "Default Code Generated Scenario", ReferenceObject = referenceObjectForEquatableTestScenarios, ObjectsThatAreEqualToButNotTheSameAsReferenceObject = new PrepareToSendNotificationResult[] { new PrepareToSendNotificationResult( referenceObjectForEquatableTestScenarios.ChannelToPrepareToSendOnChannelResultMap, referenceObjectForEquatableTestScenarios.CannotPrepareToSendOnChannelAction, referenceObjectForEquatableTestScenarios.ChannelsToSendOn), }, ObjectsThatAreNotEqualToReferenceObject = new PrepareToSendNotificationResult[] { new PrepareToSendNotificationResult( A.Dummy <PrepareToSendNotificationResult>().Whose(_ => (!_.ChannelToPrepareToSendOnChannelResultMap.IsEqualTo(referenceObjectForEquatableTestScenarios.ChannelToPrepareToSendOnChannelResultMap)) && referenceObjectForEquatableTestScenarios.ChannelsToSendOn.All(c => _.ChannelToPrepareToSendOnChannelResultMap.ContainsKey(c))).ChannelToPrepareToSendOnChannelResultMap, referenceObjectForEquatableTestScenarios.CannotPrepareToSendOnChannelAction, referenceObjectForEquatableTestScenarios.ChannelsToSendOn), new PrepareToSendNotificationResult( referenceObjectForEquatableTestScenarios.ChannelToPrepareToSendOnChannelResultMap, A.Dummy <PrepareToSendNotificationResult>().Whose(_ => !_.CannotPrepareToSendOnChannelAction.IsEqualTo(referenceObjectForEquatableTestScenarios.CannotPrepareToSendOnChannelAction)).CannotPrepareToSendOnChannelAction, referenceObjectForEquatableTestScenarios.ChannelsToSendOn), new PrepareToSendNotificationResult( referenceObjectForEquatableTestScenarios.ChannelToPrepareToSendOnChannelResultMap, referenceObjectForEquatableTestScenarios.CannotPrepareToSendOnChannelAction, A.Dummy <PrepareToSendNotificationResult>().Whose(_ => (!_.ChannelsToSendOn.IsEqualTo(referenceObjectForEquatableTestScenarios.ChannelsToSendOn)) && _.ChannelsToSendOn.All(c => referenceObjectForEquatableTestScenarios.ChannelToPrepareToSendOnChannelResultMap.ContainsKey(c))).ChannelsToSendOn), }, ObjectsThatAreNotOfTheSameTypeAsReferenceObject = new object[] { A.Dummy <object>(), A.Dummy <string>(), A.Dummy <int>(), A.Dummy <int?>(), A.Dummy <Guid>(), }, }); }
public NotificationDummyFactory() { /* Add any overriding or custom registrations here. */ // enums AutoFixtureBackedDummyFactory.ConstrainDummyToExclude(CannotPrepareToSendOnChannelAction.Unknown); AutoFixtureBackedDummyFactory.ConstrainDummyToExclude(DeliveryChannelAction.Unknown); AutoFixtureBackedDummyFactory.ConstrainDummyToExclude(FailureAction.Unknown); AutoFixtureBackedDummyFactory.ConstrainDummyToExclude(PrepareToSendOnChannelFailureAction.Unknown); AutoFixtureBackedDummyFactory.ConstrainDummyToExclude(AttemptToSendNotificationOutcome.Unknown); AutoFixtureBackedDummyFactory.ConstrainDummyToExclude(ChannelOperationOutcome.Unknown); AutoFixtureBackedDummyFactory.ConstrainDummyToExclude(GetAudienceOutcome.Unknown); AutoFixtureBackedDummyFactory.ConstrainDummyToExclude(GetDeliveryChannelConfigsOutcome.Unknown); AutoFixtureBackedDummyFactory.ConstrainDummyToExclude(PrepareToSendNotificationOutcome.Unknown); AutoFixtureBackedDummyFactory.ConstrainDummyToExclude(PrepareToSendOnChannelOutcome.Unknown); // interfaces AutoFixtureBackedDummyFactory.AddDummyCreator <IOperation>(A.Dummy <OperationBase>);// remove when moved to Protocol Dummy Factory AutoFixtureBackedDummyFactory.UseRandomInterfaceImplementationForDummy <IAudience>(); AutoFixtureBackedDummyFactory.UseRandomInterfaceImplementationForDummy <IDeliveryChannel>(); AutoFixtureBackedDummyFactory.UseRandomInterfaceImplementationForDummy <IFailure>(); AutoFixtureBackedDummyFactory.UseRandomInterfaceImplementationForDummy <INotification>(); // events AutoFixtureBackedDummyFactory.AddDummyCreator(() => new CouldNotSendOnAnyPreparedChannelEvent( A.Dummy <long>(), A.Dummy <UtcDateTime>(), A.Dummy <AttemptToSendNotificationResult>().Whose(_ => _.GetOutcome() == AttemptToSendNotificationOutcome.CouldNotSendOnAnyPreparedChannel))); AutoFixtureBackedDummyFactory.AddDummyCreator(() => new SentOnAllPreparedChannelsEvent( A.Dummy <long>(), A.Dummy <UtcDateTime>(), A.Dummy <AttemptToSendNotificationResult>().Whose(_ => _.GetOutcome() == AttemptToSendNotificationOutcome.SentOnAllPreparedChannels))); AutoFixtureBackedDummyFactory.AddDummyCreator(() => new SentOnSomePreparedChannelsEvent( A.Dummy <long>(), A.Dummy <UtcDateTime>(), A.Dummy <AttemptToSendNotificationResult>().Whose(_ => _.GetOutcome() == AttemptToSendNotificationOutcome.SentOnSomePreparedChannels))); AutoFixtureBackedDummyFactory.AddDummyCreator(() => new CouldNotGetOrUseAudienceEvent( A.Dummy <long>(), A.Dummy <UtcDateTime>(), A.Dummy <GetAudienceResult>().Whose(_ => (_.GetOutcome() != GetAudienceOutcome.GotAudienceWithNoFailuresReported) && (_.GetOutcome() != GetAudienceOutcome.GotAudienceWithReportedFailuresIgnored)))); AutoFixtureBackedDummyFactory.AddDummyCreator(() => new CouldNotGetOrUseDeliveryChannelConfigsEvent( A.Dummy <long>(), A.Dummy <UtcDateTime>(), GetPassingAudienceResult(), A.Dummy <GetDeliveryChannelConfigsResult>().Whose(_ => (_.GetOutcome() != GetDeliveryChannelConfigsOutcome.GotDeliveryChannelConfigsWithNoFailuresReported) && (_.GetOutcome() != GetDeliveryChannelConfigsOutcome.GotDeliveryChannelConfigsWithReportedFailuresIgnored)))); AutoFixtureBackedDummyFactory.AddDummyCreator(() => new AudienceOptedOutOfAllChannelsEvent( A.Dummy <long>(), A.Dummy <UtcDateTime>(), GetPassingAudienceResult(), GetPassingDeliveryChannelConfigsResult(), A.Dummy <PrepareToSendNotificationResult>().Whose(_ => (_.GetOutcome() == PrepareToSendNotificationOutcome.AudienceOptedOutOfAllChannels)))); AutoFixtureBackedDummyFactory.AddDummyCreator(() => new CouldNotPrepareToSendOnAnyChannelEvent( A.Dummy <long>(), A.Dummy <UtcDateTime>(), GetPassingAudienceResult(), GetPassingDeliveryChannelConfigsResult(), A.Dummy <PrepareToSendNotificationResult>().Whose(_ => (_.GetOutcome() == PrepareToSendNotificationOutcome.CouldNotPrepareToSendOnAnyChannelDespiteAttemptingAll) || (_.GetOutcome() == PrepareToSendNotificationOutcome.CouldNotPrepareToSendOnAnyChannelBecauseOneForcedAllToBeDiscarded)))); AutoFixtureBackedDummyFactory.AddDummyCreator(() => new PreparedToSendOnAllChannelsEvent( A.Dummy <long>(), A.Dummy <UtcDateTime>(), GetPassingAudienceResult(), GetPassingDeliveryChannelConfigsResult(), A.Dummy <PrepareToSendNotificationResult>().Whose(_ => (_.GetOutcome() == PrepareToSendNotificationOutcome.PreparedToSendOnAllChannels)))); AutoFixtureBackedDummyFactory.AddDummyCreator(() => new PreparedToSendOnSomeChannelsEvent( A.Dummy <long>(), A.Dummy <UtcDateTime>(), GetPassingAudienceResult(), GetPassingDeliveryChannelConfigsResult(), A.Dummy <PrepareToSendNotificationResult>().Whose(_ => (_.GetOutcome() == PrepareToSendNotificationOutcome.PreparedToSendOnSomeChannels)))); AutoFixtureBackedDummyFactory.AddDummyCreator(() => new SendNotificationRequestedEvent( A.Dummy <long>(), A.Dummy <UtcDateTime>(), A.Dummy <SendNotificationOp>())); // model classes AutoFixtureBackedDummyFactory.AddDummyCreator(() => { var channelToOperationsOutcomeInfoMap = new Dictionary <IDeliveryChannel, IReadOnlyCollection <ChannelOperationOutcomeInfo> >(); var randomIndex = ThreadSafeRandom.Next(1, 4); var randomChannels = new IDeliveryChannel[] { new SlackDeliveryChannel(), new EmailDeliveryChannel() }.RandomizeElements().ToArray(); if (randomIndex == 1) { // SentOnAllPreparedChannels randomChannels = randomChannels.Take(ThreadSafeRandom.Next(1, randomChannels.Length + 1)).ToArray(); foreach (var randomChannel in randomChannels) { channelToOperationsOutcomeInfoMap.Add( randomChannel, Some.ReadOnlyDummies <ChannelOperationOutcomeInfo>().Whose(_ => _.All(o => o.Outcome == ChannelOperationOutcome.Succeeded)).ToList()); } } else if (randomIndex == 2) { // SentOnSomePreparedChannels channelToOperationsOutcomeInfoMap.Add( randomChannels[0], Some.ReadOnlyDummies <ChannelOperationOutcomeInfo>().Whose(_ => _.Select(o => o.Outcome).Distinct().Count() > 1).ToList()); channelToOperationsOutcomeInfoMap.Add( randomChannels[1], Some.ReadOnlyDummies <ChannelOperationOutcomeInfo>().Whose(_ => _.All(o => o.Outcome == ChannelOperationOutcome.Succeeded)).ToList()); } else { // CouldNotSendOnAnyPreparedChannel channelToOperationsOutcomeInfoMap.Add( randomChannels[0], Some.ReadOnlyDummies <ChannelOperationOutcomeInfo>().Whose(_ => _.Select(o => o.Outcome).Distinct().Count() > 1).ToList()); channelToOperationsOutcomeInfoMap.Add( randomChannels[1], Some.ReadOnlyDummies <ChannelOperationOutcomeInfo>().Whose(_ => _.All(o => o.Outcome == ChannelOperationOutcome.Failed)).ToList()); } var result = new AttemptToSendNotificationResult(channelToOperationsOutcomeInfoMap); return(result); }); AutoFixtureBackedDummyFactory.AddDummyCreator(() => { var randomIndex = ThreadSafeRandom.Next(1, 6); GetAudienceResult result; if (randomIndex == 1) { // GotAudienceWithNoFailuresReported result = new GetAudienceResult(A.Dummy <IAudience>(), null, A.Dummy <FailureAction>()); } else if (randomIndex == 2) { // GotAudienceWithReportedFailuresIgnored result = new GetAudienceResult(A.Dummy <IAudience>(), Some.ReadOnlyDummies <IFailure>().ToList(), FailureAction.IgnoreAndProceedIfPossibleOtherwiseStop); } else if (randomIndex == 3) { // CouldNotGetAudienceAndNoFailuresReported if (ThreadSafeRandom.Next(2) == 0) { result = new GetAudienceResult(null, null, A.Dummy <FailureAction>()); } else { result = new GetAudienceResult(null, new IFailure[0], A.Dummy <FailureAction>()); } } else if (randomIndex == 4) { // CouldNotGetAudienceWithSomeFailuresReported result = new GetAudienceResult(null, Some.ReadOnlyDummies <IFailure>().ToList(), A.Dummy <FailureAction>()); } else { // DespiteGettingAudienceFailuresPreventUsingIt result = new GetAudienceResult(A.Dummy <IAudience>(), Some.ReadOnlyDummies <IFailure>().ToList(), FailureAction.Stop); } return(result); }); AutoFixtureBackedDummyFactory.AddDummyCreator(() => { var randomChannels = new IDeliveryChannel[] { new SlackDeliveryChannel(), new EmailDeliveryChannel() }; randomChannels = randomChannels.RandomizeElements().Take(ThreadSafeRandom.Next(1, randomChannels.Length + 1)).ToArray(); var deliveryChannelConfigs = randomChannels.Select(_ => new DeliveryChannelConfig(_, A.Dummy <DeliveryChannelAction>())).ToList(); var randomIndex = ThreadSafeRandom.Next(1, 6); GetDeliveryChannelConfigsResult result; if (randomIndex == 1) { // GotDeliveryChannelConfigsWithNoFailuresReported result = new GetDeliveryChannelConfigsResult( deliveryChannelConfigs, null, A.Dummy <FailureAction>()); } else if (randomIndex == 2) { // GotDeliveryChannelConfigsWithReportedFailuresIgnored result = new GetDeliveryChannelConfigsResult( deliveryChannelConfigs, Some.ReadOnlyDummies <IFailure>().ToList(), FailureAction.IgnoreAndProceedIfPossibleOtherwiseStop); } else if (randomIndex == 3) { // CouldNotGetDeliveryChannelConfigsAndNoFailuresReported result = new GetDeliveryChannelConfigsResult(null, null, A.Dummy <FailureAction>()); } else if (randomIndex == 4) { // CouldNotGetDeliveryChannelConfigsWithSomeFailuresReported result = new GetDeliveryChannelConfigsResult(null, Some.ReadOnlyDummies <IFailure>().ToList(), A.Dummy <FailureAction>()); } else { // DespiteGettingDeliveryChannelConfigsFailuresPreventUsingThem result = new GetDeliveryChannelConfigsResult( deliveryChannelConfigs, Some.ReadOnlyDummies <IFailure>().ToList(), FailureAction.Stop); } return(result); }); AutoFixtureBackedDummyFactory.AddDummyCreator(() => { var randomChannels = new IDeliveryChannel[] { new SlackDeliveryChannel(), new EmailDeliveryChannel() }.RandomizeElements().ToArray(); var randomIndex = ThreadSafeRandom.Next(1, 6); PrepareToSendNotificationResult result; if (randomIndex == 1) { // AudienceOptedOutOfAllChannels result = new PrepareToSendNotificationResult( new Dictionary <IDeliveryChannel, PrepareToSendOnChannelResult>(), A.Dummy <CannotPrepareToSendOnChannelAction>(), new IDeliveryChannel[0]); } else if (randomIndex == 2) { // PreparedToSendOnAllChannels var channelToPrepareToSendOnChannelResultMap = new Dictionary <IDeliveryChannel, PrepareToSendOnChannelResult>(); foreach (var randomChannel in randomChannels) { channelToPrepareToSendOnChannelResultMap.Add( randomChannel, new PrepareToSendOnChannelResult(GetChannelOperationInstructions(), null, A.Dummy <PrepareToSendOnChannelFailureAction>())); } result = new PrepareToSendNotificationResult( channelToPrepareToSendOnChannelResultMap, A.Dummy <CannotPrepareToSendOnChannelAction>(), randomChannels); } else if (randomIndex == 3) { // PreparedToSendOnSomeChannels result = new PrepareToSendNotificationResult( new Dictionary <IDeliveryChannel, PrepareToSendOnChannelResult> { { randomChannels[0], new PrepareToSendOnChannelResult( GetChannelOperationInstructions(), Some.ReadOnlyDummies <IFailure>().ToList(), PrepareToSendOnChannelFailureAction.IgnoreAndProceedIfPossibleOtherwiseDoNotSendOnChannel) }, { randomChannels[1], new PrepareToSendOnChannelResult( null, null, PrepareToSendOnChannelFailureAction.IgnoreAndProceedIfPossibleOtherwiseDoNotSendOnChannel) }, }, CannotPrepareToSendOnChannelAction.ContinueAndAttemptPreparingToSendOnNextChannel, new IDeliveryChannel[] { randomChannels[0] }); } else if (randomIndex == 4) { // CouldNotPrepareToSendOnAnyChannelDespiteAttemptingAll result = new PrepareToSendNotificationResult( new Dictionary <IDeliveryChannel, PrepareToSendOnChannelResult> { { new SlackDeliveryChannel(), new PrepareToSendOnChannelResult( null, null, PrepareToSendOnChannelFailureAction.IgnoreAndProceedIfPossibleOtherwiseDoNotSendOnChannel) }, { new EmailDeliveryChannel(), new PrepareToSendOnChannelResult( GetChannelOperationInstructions(), Some.ReadOnlyDummies <IFailure>().ToList(), PrepareToSendOnChannelFailureAction.DoNotSendOnChannel) }, }, CannotPrepareToSendOnChannelAction.ContinueAndAttemptPreparingToSendOnNextChannel, new IDeliveryChannel[0]); } else { // CouldNotPrepareToSendOnAnyChannelBecauseOneForcedAllToBeDiscarded result = new PrepareToSendNotificationResult( new Dictionary <IDeliveryChannel, PrepareToSendOnChannelResult> { { randomChannels[0], new PrepareToSendOnChannelResult( GetChannelOperationInstructions(), Some.ReadOnlyDummies <IFailure>().ToList(), PrepareToSendOnChannelFailureAction.DoNotSendOnChannel) }, }, CannotPrepareToSendOnChannelAction.StopAndNotDoNotSendOnAnyChannel, new IDeliveryChannel[0]); } return(result); }); AutoFixtureBackedDummyFactory.AddDummyCreator(() => { var randomIndex = ThreadSafeRandom.Next(1, 6); PrepareToSendOnChannelResult result; if (randomIndex == 1) { // PreparedToSendOnChannelWithNoFailuresReported result = new PrepareToSendOnChannelResult( GetChannelOperationInstructions(), null, A.Dummy <PrepareToSendOnChannelFailureAction>()); } else if (randomIndex == 2) { // PreparedToSendOnChannelWithReportedFailuresIgnored result = new PrepareToSendOnChannelResult( GetChannelOperationInstructions(), Some.ReadOnlyDummies <IFailure>().ToList(), PrepareToSendOnChannelFailureAction.IgnoreAndProceedIfPossibleOtherwiseDoNotSendOnChannel); } else if (randomIndex == 3) { // CouldNotPrepareToSendOnChannelAndNoFailuresReported if (ThreadSafeRandom.Next(2) == 0) { result = new PrepareToSendOnChannelResult( null, null, PrepareToSendOnChannelFailureAction.IgnoreAndProceedIfPossibleOtherwiseDoNotSendOnChannel); } else { result = new PrepareToSendOnChannelResult( new ChannelOperationInstruction[0], new IFailure[0], PrepareToSendOnChannelFailureAction.IgnoreAndProceedIfPossibleOtherwiseDoNotSendOnChannel); } } else if (randomIndex == 4) { // CouldNotPrepareToSendOnChannelWithSomeFailuresReported result = new PrepareToSendOnChannelResult( null, Some.ReadOnlyDummies <IFailure>().ToList(), PrepareToSendOnChannelFailureAction.IgnoreAndProceedIfPossibleOtherwiseDoNotSendOnChannel); } else { // DespitePreparingToSendOnChannelFailuresPreventUsingIt result = new PrepareToSendOnChannelResult( GetChannelOperationInstructions(), Some.ReadOnlyDummies <IFailure>().ToList(), PrepareToSendOnChannelFailureAction.DoNotSendOnChannel); } return(result); }); AutoFixtureBackedDummyFactory.AddDummyCreator(() => { var succeededEventType = A.Dummy <TypeRepresentation>(); var failedEventType = A.Dummy <TypeRepresentation>().ThatIsNot(succeededEventType); var result = new ChannelOperationMonitoringInfo(A.Dummy <long>(), succeededEventType, failedEventType); return(result); }); }
/// <inheritdoc /> public override async Task ExecuteAsync( HandleRecordOp <ExecuteOpRequestedEvent <long, SendNotificationOp> > operation) { new { operation }.AsArg().Must().NotBeNull(); // Pull some info out of the operation. var trackingCodeId = operation.RecordToHandle.Payload.Id; var sendNotificationOp = operation.RecordToHandle.Payload.Operation; var notification = sendNotificationOp.Notification; var tags = operation.RecordToHandle.Metadata.Tags; // Write SendNotificationRequestedEvent to the Event Stream (creates the Notification Aggregate). await this.PutSendNotificationRequestedEventAsync(sendNotificationOp, trackingCodeId, tags); // Get the audience and write CannotGetOrUseAudienceEvent // to the Event Stream if there is none of if we should stop on failures. var getAudienceResult = await this.GetAudienceAsync(notification); var getAudienceOutcome = getAudienceResult.GetOutcome(); if ((getAudienceOutcome != GetAudienceOutcome.GotAudienceWithNoFailuresReported) && (getAudienceOutcome != GetAudienceOutcome.GotAudienceWithReportedFailuresIgnored)) { await this.PutCannotGetOrUseAudienceEventAsync(getAudienceResult, trackingCodeId, tags); return; } // Get the delivery channel configs and write CannotGetOrUseDeliveryChannelConfigsEvent // to the Event Stream if there are none or if we should stop on failures. var audience = getAudienceResult.Audience; var getDeliveryChannelConfigsResult = await this.GetDeliveryChannelConfigsAsync(notification, getAudienceResult.Audience); var getDeliveryChannelConfigsOutcome = getDeliveryChannelConfigsResult.GetOutcome(); if ((getDeliveryChannelConfigsOutcome != GetDeliveryChannelConfigsOutcome.GotDeliveryChannelConfigsWithNoFailuresReported) && (getDeliveryChannelConfigsOutcome != GetDeliveryChannelConfigsOutcome.GotDeliveryChannelConfigsWithReportedFailuresIgnored)) { await this.PutCannotGetOrUseDeliveryChannelConfigsEventAsync(getAudienceResult, getDeliveryChannelConfigsResult, trackingCodeId, tags); return; } // Prepare the notification to be sent to the audience on all channels configured for sending. var channelConfigs = getDeliveryChannelConfigsResult.Configs; var channelToPrepareToSendOnChannelResultMap = new Dictionary <IDeliveryChannel, PrepareToSendOnChannelResult>(); var channelToOperationInstructionsMap = new Dictionary <IDeliveryChannel, IReadOnlyList <ChannelOperationInstruction> >(); foreach (var channelConfig in channelConfigs) { if (channelConfig.Action == DeliveryChannelAction.AudienceOptedOut) { continue; } else if (channelConfig.Action == DeliveryChannelAction.SendOnChannel) { // no-op } else { throw new NotSupportedException(Invariant($"This {nameof(DeliveryChannelAction)} is not supported: {channelConfig.Action}.")); } var channel = channelConfig.Channel; var prepareToSendOnChannelResult = await this.PrepareToSendOnChannelAsync(notification, audience, channel, tags); var prepareToSendOnChannelOutcome = prepareToSendOnChannelResult.GetOutcome(); channelToPrepareToSendOnChannelResultMap.Add(channel, prepareToSendOnChannelResult); if ((prepareToSendOnChannelOutcome == PrepareToSendOnChannelOutcome.PreparedToSendOnChannelWithNoFailuresReported) || (prepareToSendOnChannelOutcome == PrepareToSendOnChannelOutcome.PreparedToSendOnChannelWithReportedFailuresIgnored)) { new { this.channelToOperationStreamMap }.AsOp().Must().ContainKey(channel, Invariant($"Staging to send on channel {channel.GetType().ToStringReadable()} but there is no operation stream associated with that channel.")); channelToOperationInstructionsMap.Add(channel, prepareToSendOnChannelResult.ChannelOperationInstructions); } else { if (this.cannotPrepareToSendOnChannelAction == CannotPrepareToSendOnChannelAction.ContinueAndAttemptPreparingToSendOnNextChannel) { // no-op } else if (this.cannotPrepareToSendOnChannelAction == CannotPrepareToSendOnChannelAction.StopAndNotDoNotSendOnAnyChannel) { // discard all channel operations channelToOperationInstructionsMap = new Dictionary <IDeliveryChannel, IReadOnlyList <ChannelOperationInstruction> >(); break; } else { throw new NotSupportedException(Invariant($"This {nameof(CannotPrepareToSendOnChannelAction)} is not supported: {this.cannotPrepareToSendOnChannelAction}.")); } } } var prepareToSendNotificationResult = new PrepareToSendNotificationResult(channelToPrepareToSendOnChannelResultMap, this.cannotPrepareToSendOnChannelAction, channelToOperationInstructionsMap.Keys.ToList()); var prepareToSendNotificationOutcome = prepareToSendNotificationResult.GetOutcome(); await this.PutPrepareToSendNotificationEventAsync(prepareToSendNotificationOutcome, getAudienceResult, getDeliveryChannelConfigsResult, prepareToSendNotificationResult, trackingCodeId, tags); // Is at least one channel is prepared for sending? Continue. if ((prepareToSendNotificationOutcome != PrepareToSendNotificationOutcome.PreparedToSendOnAllChannels) && (prepareToSendNotificationOutcome != PrepareToSendNotificationOutcome.PreparedToSendOnSomeChannels)) { return; } // Create a Saga to track channel operations. await this.PutSagaAsync(trackingCodeId, channelToOperationInstructionsMap, tags); // Push the channel-operations to their streams. foreach (var channel in channelToOperationInstructionsMap.Keys) { var channelOperationInstructions = channelToOperationInstructionsMap[channel]; await this.PutChannelOperationsAsync(channel, channelOperationInstructions); } }