예제 #1
0
        public async Task PiggyBack_PullRequest_With_Receipt_Operation_Becomes_DeadLettered_When_Retries_Are_Exhausted()
        {
            // Arrange
            string pullSendUrl = RetrievePullingUrlFromConfig();

            var user    = new UserMessage($"user-{Guid.NewGuid()}", PullRequestMpc);
            var receipt = new Receipt($"receipt-{Guid.NewGuid()}", user.MessageId);

            InsertUserMessage(user);
            long id = InsertReceipt(receipt, pullSendUrl, Operation.ToBePiggyBacked);

            // Act
            InsertRetryReliability(id, maxRetryCount: 1);

            // Assert
            await PollUntilPresent(
                () => _databaseSpy.GetOutMessageFor(
                    m => m.EbmsMessageId == receipt.MessageId &&
                    m.Operation == Operation.DeadLettered),
                timeout : TimeSpan.FromSeconds(40));

            RetryReliability reliability = await PollUntilPresent(
                () => _databaseSpy.GetRetryReliabilityFor(
                    r => r.RefToOutMessageId == id &&
                    r.Status == RetryStatus.Completed),
                timeout : TimeSpan.FromSeconds(5));

            Assert.True(
                reliability.CurrentRetryCount > 0,
                "RetryReliability.CurrentRetryCount should be greater then zero");
        }
예제 #2
0
 private void InsertRetryReliability(long id, int maxRetryCount)
 {
     _databaseSpy.InsertRetryReliability(
         RetryReliability.CreateForOutMessage(
             refToOutMessageId: id,
             maxRetryCount: maxRetryCount,
             retryInterval: TimeSpan.FromMilliseconds(1),
             type: RetryType.PiggyBack));
 }
        public async Task OutMessage_Is_Set_To_Sent_When_Retry_Happen_Within_Allowed_MaxRetry(
            HttpStatusCode secondAttempt,
            Operation expected)
        {
            await TestComponentWithSettings(
                "sendagent_settings.xml",
                async (settings, as4Msh) =>
            {
                // Arrange
                const string url            = "http://localhost:7171/business/sending/";
                SendingProcessingMode pmode = ReceptionAwarenessSendingPMode(url);
                OutMessage im = CreateOutMessageRefStoredAS4Message(as4Msh);

                InsertMessageEntityWithRetry(
                    entity: im,
                    config: as4Msh.GetConfiguration(),
                    pmode: pmode,
                    createRetry: id => RetryReliability.CreateForOutMessage(
                        id,
                        pmode.Reliability.ReceptionAwareness.RetryCount,
                        pmode.Reliability.ReceptionAwareness.RetryInterval.AsTimeSpan(),
                        RetryType.Send));

                // Act
                SimulateSendingFailureOnFirstAttempt(url, secondAttempt);

                // Assert
                var spy         = new DatabaseSpy(as4Msh.GetConfiguration());
                OutMessage sent = await PollUntilPresent(
                    () => spy.GetOutMessageFor(m => m.Operation == expected),
                    timeout: TimeSpan.FromSeconds(10));
                Assert.Equal(im.EbmsMessageId, sent.EbmsMessageId);

                RetryReliability referenced = await PollUntilPresent(
                    () => spy.GetRetryReliabilityFor(r => r.RefToOutMessageId == sent.Id),
                    timeout: TimeSpan.FromSeconds(5));
                Assert.Equal(RetryStatus.Completed, referenced.Status);

                InMessage deadLetteredError =
                    spy.GetInMessageFor(m => m.EbmsRefToMessageId == sent.EbmsMessageId);

                bool storedDeadLetteredError =
                    deadLetteredError?.Operation == Operation.ToBeNotified &&
                    deadLetteredError?.EbmsMessageType == MessageType.Error;

                Assert.True(
                    storedDeadLetteredError == (expected == Operation.DeadLettered),
                    "Expected to have stored AS4 Error for DeadLettered message");
            });
        }
예제 #4
0
        public async Task Update_RetryReliability_To_Pending_When_Receiver_Is_Offline()
        {
            // Arrange
            string     ebmsMessageId   = $"user-{Guid.NewGuid()}";
            AS4Message tobeSendMessage = AS4Message.Create(new UserMessage(ebmsMessageId));

            var outMessage = new OutMessage(ebmsMessageId);

            GetDataStoreContext.InsertOutMessage(outMessage);
            GetDataStoreContext.InsertRetryReliability(
                RetryReliability.CreateForOutMessage(
                    refToOutMessageId: outMessage.Id,
                    maxRetryCount: 2,
                    retryInterval: TimeSpan.FromSeconds(1),
                    type: RetryType.Send));

            var ctx = new MessagingContext(
                tobeSendMessage,
                new ReceivedEntityMessage(
                    outMessage,
                    tobeSendMessage.ToStream(),
                    tobeSendMessage.ContentType),
                MessagingContextMode.Send)
            {
                SendingPMode = CreateSendPModeWithPushUrl()
            };

            var   sabotageException = new WebException("Remote host not available");
            IStep sut = CreateSendStepWithResponse(
                StubHttpClient.ThatThrows(sabotageException));

            // Act
            StepResult result = await sut.ExecuteAsync(ctx);

            // Assert
            Assert.False(result.Succeeded);
            GetDataStoreContext.AssertRetryRelatedOutMessage(
                outMessage.Id,
                r =>
            {
                Assert.NotNull(r);
                Assert.Equal(RetryStatus.Pending, r.Status);
            });
        }
        private static void InsertMessageEntityWithRetry(
            OutMessage entity,
            IConfig config,
            SendingProcessingMode pmode,
            Func <long, RetryReliability> createRetry)
        {
            using (var ctx = new DatastoreContext(config))
            {
                entity.SetPModeInformation(pmode);
                entity.Operation = Operation.ToBeSent;

                ctx.OutMessages.Add(entity);
                ctx.SaveChanges();

                RetryReliability r = createRetry(entity.Id);
                ctx.RetryReliability.Add(r);
                ctx.SaveChanges();
            }
        }
예제 #6
0
        public async Task Message_Is_Set_To_Exception_If_Delivery_Fails_After_Exhausted_Retries()
        {
            // Arrang
            AS4Message as4Message = CreateAS4Message();

            // Act
            await TestDeliverRetryByBlockingDeliveryLocationFor(as4Message, TimeSpan.FromSeconds(30));

            // Assert
            InMessage actual =
                await PollUntilPresent(
                    () => _databaseSpy.GetInMessageFor(m => m.Operation == Operation.DeadLettered),
                    timeout : TimeSpan.FromSeconds(10));

            RetryReliability rr =
                _databaseSpy.GetRetryReliabilityFor(r => r.RefToInMessageId == actual.Id);

            Assert.Equal(rr.CurrentRetryCount, rr.MaxRetryCount);
            Assert.Equal(RetryStatus.Completed, rr.Status);
        }
        public async Task Reset_InMessage_Operation_ToBeDelivered_When_CurrentRetry_LessThen_MaxRetry(DeliverRetry input)
        {
            // Arrange
            string id = Guid.NewGuid().ToString();

            InMessage im = CreateInMessage(id, InStatus.Received, Operation.Delivering);

            GetDataStoreContext.InsertInMessage(im);

            var r = RetryReliability.CreateForInMessage(
                refToInMessageId: im.Id,
                maxRetryCount: input.MaxRetryCount,
                retryInterval: default(TimeSpan),
                type: RetryType.Notification);

            r.CurrentRetryCount = input.CurrentRetryCount;
            GetDataStoreContext.InsertRetryReliability(r);

            DeliverMessageEnvelope envelope = AnonymousDeliverEnvelope(id);

            var stub = new Mock <IDeliverSender>();

            stub.Setup(s => s.SendAsync(envelope))
            .ReturnsAsync(input.SendResult);

            IStep sut = CreateSendDeliverStepWithSender(stub.Object);

            // Act
            await sut.ExecuteAsync(new MessagingContext(envelope) { ReceivingPMode = CreateDefaultReceivingPMode() });

            // Assert
            GetDataStoreContext.AssertInMessage(id, inMessage =>
            {
                Assert.NotNull(inMessage);
                Assert.Equal(input.ExpectedStatus, inMessage.Status.ToEnum <InStatus>());
                Assert.Equal(input.ExpectedOperation, inMessage.Operation);
            });
        }
예제 #8
0
        public async Task Message_Is_Set_To_Delivered_After_Its_Being_Retried()
        {
            // Arrang
            AS4Message as4Message = CreateAS4Message();

            // Act
            await TestDeliverRetryByBlockingDeliveryLocationFor(as4Message, TimeSpan.FromSeconds(1));

            // Assert
            InMessage actual =
                await PollUntilPresent(
                    () => _databaseSpy.GetInMessageFor(m => m.Operation == Operation.Delivered),
                    timeout : TimeSpan.FromSeconds(10));

            // Assert
            Assert.Equal(InStatus.Delivered, actual.Status.ToEnum <InStatus>());
            Assert.Equal(Operation.Delivered, actual.Operation);

            RetryReliability rr = _databaseSpy.GetRetryReliabilityFor(r => r.RefToInMessageId == actual.Id);

            Assert.True(0 < rr.CurrentRetryCount, "0 < actualMessage.CurrentRetryCount");
            Assert.Equal(RetryStatus.Completed, rr.Status);
        }
예제 #9
0
        public async Task Retries_Uploading_When_Uploader_Returns_RetryableFail_Result(UploadRetry input)
        {
            // Arrange
            string    id = "deliver-" + Guid.NewGuid();
            InMessage im = InsertInMessage(id);

            var r = RetryReliability.CreateForInMessage(
                refToInMessageId: im.Id,
                maxRetryCount: input.MaxRetryCount,
                retryInterval: default(TimeSpan),
                type: RetryType.Delivery);

            r.CurrentRetryCount = input.CurrentRetryCount;
            GetDataStoreContext.InsertRetryReliability(r);

            var        a           = new FilledAttachment();
            var        userMessage = new FilledUserMessage(id, a.Id);
            AS4Message as4Msg      = AS4Message.Create(userMessage);

            as4Msg.AddAttachment(a);

            MessagingContext fixture = await PrepareAS4MessageForDeliveryAsync(as4Msg, CreateReceivingPModeWithPayloadMethod());

            IAttachmentUploader stub = CreateStubAttachmentUploader(fixture.DeliverMessage.Message.MessageInfo, input.UploadResult);

            // Act
            await CreateUploadStep(stub).ExecuteAsync(fixture);

            // Assert
            GetDataStoreContext.AssertInMessage(id, actual =>
            {
                Assert.NotNull(actual);
                Assert.Equal(input.ExpectedStatus, actual.Status.ToEnum <InStatus>());
                Assert.Equal(input.ExpectedOperation, actual.Operation);
            });
        }
예제 #10
0
        /// <summary>
        /// Mark the stored <see cref="OutMessage"/> for retry/delayed piggy backing.
        /// </summary>
        /// <param name="inserts"></param>
        /// <param name="reliability"></param>
        internal void InsertRetryForPiggyBackedSignalMessages(IEnumerable <OutMessage> inserts, Model.PMode.RetryReliability reliability)
        {
            if (reliability?.IsEnabled == true)
            {
                foreach (OutMessage m in inserts.Where(i => i.Operation == Operation.ToBePiggyBacked))
                {
                    var r = RetryReliability.CreateForOutMessage(
                        refToOutMessageId: m.Id,
                        maxRetryCount: reliability.RetryCount,
                        retryInterval: reliability.RetryInterval.AsTimeSpan(),
                        type: RetryType.PiggyBack);

                    Logger.Debug(
                        $"Insert RetryReliability for ToBePiggyBacked SignalMessage OutMessage {m.EbmsMessageId} with "
                        + $"{{RetryCount={r.MaxRetryCount}, RetryInterval={r.RetryInterval}}}");

                    _repository.InsertRetryReliability(r);
                }
            }
            else
            {
                Logger.Debug("Will not insert RetryReliability because ReceivingPMode.ReplyHandling.Reliability is not enabeld");
            }
        }
예제 #11
0
        public async Task All_Attachments_Should_Succeed_Or_Fail(UploadRetry input)
        {
            // Arrange
            string    id = "deliver-" + Guid.NewGuid();
            InMessage im = InsertInMessage(id);

            var r = RetryReliability.CreateForInMessage(
                refToInMessageId: im.Id,
                maxRetryCount: input.MaxRetryCount,
                retryInterval: default(TimeSpan),
                type: RetryType.Delivery);

            r.CurrentRetryCount = input.CurrentRetryCount;
            GetDataStoreContext.InsertRetryReliability(r);


            var a1          = new FilledAttachment("attachment-1");
            var a2          = new FilledAttachment("attachment-2");
            var userMessage = new FilledUserMessage(id, a1.Id, a2.Id);

            var as4Msg = AS4Message.Create(userMessage);

            as4Msg.AddAttachment(a1);
            as4Msg.AddAttachment(a2);

            MessagingContext fixture = await PrepareAS4MessageForDeliveryAsync(as4Msg, CreateReceivingPModeWithPayloadMethod());

            var stub = new Mock <IAttachmentUploader>();

            stub.Setup(s => s.UploadAsync(a1, fixture.DeliverMessage.Message.MessageInfo))
            .ReturnsAsync(input.UploadResult);
            stub.Setup(s => s.UploadAsync(a2, fixture.DeliverMessage.Message.MessageInfo))
            .ReturnsAsync(
                input.UploadResult.Status == SendResult.Success
                        ? UploadResult.FatalFail
                        : UploadResult.RetryableFail);

            // Act
            await CreateUploadStep(stub.Object).ExecuteAsync(fixture);

            // Assert
            GetDataStoreContext.AssertInMessage(id, actual =>
            {
                Assert.NotNull(actual);
                Operation op = actual.Operation;
                Assert.NotEqual(Operation.Delivered, op);
                InStatus st = actual.Status.ToEnum <InStatus>();
                Assert.NotEqual(InStatus.Delivered, st);

                bool operationToBeRetried     = Operation.ToBeRetried == op;
                bool uploadResultCanBeRetried =
                    input.UploadResult.Status == SendResult.RetryableFail &&
                    input.CurrentRetryCount < input.MaxRetryCount;

                Assert.True(
                    operationToBeRetried == uploadResultCanBeRetried,
                    "InMessage should update Operation=ToBeDelivered");

                bool messageSetToException = Operation.DeadLettered == op && InStatus.Exception == st;
                bool exhaustRetries        =
                    input.CurrentRetryCount == input.MaxRetryCount ||
                    input.UploadResult.Status != SendResult.RetryableFail;

                Assert.True(
                    messageSetToException == exhaustRetries,
                    $"{messageSetToException} != {exhaustRetries} InMessage should update Operation=DeadLettered, Status=Exception");
            });
        }