示例#1
0
            public async Task WhenTheInnerHandlerThrowsAHandledExceptionAndTheNumberOfretriesIsExceeded_ThenTheOriginalExceptionIsRethrown(Type exceptionType, string retryKey)
            {
                // arrange
                var       errorMessage    = exceptionType.ToString();
                var       testException   = (Exception)Activator.CreateInstance(exceptionType, errorMessage);
                Exception caughtException = null;

                _testQueueMessage.UserProperties[retryKey] = _maxRetryAttempts;

                var command = new SendSmsCommand(_testOutgoingSms, _testQueueMessage);

                _mockHandler
                .Setup(m => m.HandleAsync(command, It.IsAny <CancellationToken>()))
                .ThrowsAsync(testException);

                // act
                try
                {
                    await _sut.HandleAsync(command);
                }
                catch (Exception ex)
                {
                    caughtException = ex;
                }

                caughtException.Should().BeOfType(exceptionType);
            }
            public async Task WhenCalled_ThenTheConversationIsSavedToTheConversationRepository()
            {
                // arrange
                Conversation testConversation = null;
                OutgoingSms  message          = new OutgoingSmsBuilder();

                _mockConversationRepository.Setup(m =>
                                                  m.Save(It.IsAny <Conversation>()))
                .Callback <Conversation>(c =>
                {
                    c.Id.Should().Be(message.Conversation.ConversationId);
                    c.ActivityId.Should().Be(message.Conversation.ActivityId);
                    c.TurnId.Should().Be(message.Conversation.TurnId);

                    testConversation = c;
                })
                .Returns(Task.CompletedTask);

                var command = new SendSmsCommand(message, _testQueueMessage);

                // act
                await _sut.HandleAsync(command);

                //assert
                _mockConversationRepository.Verify(m => m.Save(testConversation), Times.Once);
            }
示例#3
0
        public async Task When_UserHasEnoughSmsLimit_SmsEventIsPushed()
        {
            using (var testServer = await CreateWithUserAsync())
            {
                //Add Some SMS Credits
                var dbContext = testServer.Host.Services.GetService(typeof(ApplicationDbContext))
                                as ApplicationDbContext;
                var subjectId = (testServer.Host.Services
                                 .GetRequiredService(typeof(Claim)) as Claim).Value;

                var user = await dbContext.Users.FirstAsync(u => u.SubjectId == subjectId);

                user.AddSmsBalance(2);
                await dbContext.SaveChangesAsync();

                var messages = new List <SmsMessageModel>();

                for (var i = 0; i < 2; i++)
                {
                    messages.Add(new SmsMessageModel("5544567788", "TEST", "TEST"));
                }

                var command  = new SendSmsCommand(Guid.NewGuid(), messages);
                var response = await testServer.CreateClient().PostAsync(ApiPath, command.ToJsonContent());

                response.EnsureSuccessStatusCode();

                var @event = Consumer.Instance.GetFirst <ISendSmsRequestReceived>();
                @event.UserId.Should().NotBe(default);
示例#4
0
        public async Task When_UserHasEnoughSmsLimit_SmsEventIsPushed()
        {
            using var testServer = await CreateWithUserAsync();

            var user = await testServer.GetCurrentUserInSession();

            var client = testServer.CreateClient();
            var addSmsCreditsCommand = new AddSmsCreditsCommand(Guid.NewGuid(), user.Id, 2, false);
            await client.PostAsync($"{ApiPath}/add-credits", addSmsCreditsCommand.ToJsonContent());

            var messages = new List <SmsMessageModel>();

            for (var i = 0; i < 2; i++)
            {
                messages.Add(new SmsMessageModel("5544567788", "TEST", "TEST"));
            }

            var command  = new SendSmsCommand(Guid.NewGuid(), messages);
            var response = await client.PostAsync(ApiPath, command.ToJsonContent());

            response.EnsureSuccessStatusCode();

            var @event = Consumer.Instance.GetFirst <ISendSmsRequestReceived>();

            @event.UserId.Should().NotBe(default);
        private void Handle(SmsNotificationJobContext context, UserCardBlocked cardBlocked)
        {
            var profile = VerifyProfile(context, cardBlocked.UserId);

            if (profile == null)
            {
                return;
            }
            if (!profile.SmsNotificationEnabled)
            {
                return;
            }
            var card = context.CardAccountService.GetCard(new IdentityQuery <Guid>(cardBlocked.Card.CardId));

            if (card == null)
            {
                throw new InvalidOperationException("Can't find card.");
            }
            var secureCardNo = string.Format(
                "{0}****{1}",
                new string(card.CardNo.Take(8).ToArray()),
                new string(card.CardNo.Skip(12).ToArray()));
            var cardName = string.Format("{0}('{1}')",
                                         secureCardNo,
                                         cardBlocked.Card.FriendlyName ?? cardBlocked.Card.CardVendor.Name);
            var sms = new SendSmsCommand
            {
                RecipientPhoneNumber = profile.PhoneNumber,
                Text = string.Format(SmsMessages.CardBlocked, cardName)
            };

            context.SmsService.SendSms(sms);
        }
示例#6
0
            public async Task WhenTheInnerHandlerThrowsAHandledException_ThenADelayedMessageHasItsExistingRetryPropertiesClearedBeforeSettingTheRetryCount(Type exceptionType, string retryKey)
            {
                // arrange
                var errorMessage  = Guid.NewGuid().ToString();
                var testException = (Exception)Activator.CreateInstance(exceptionType, errorMessage);

                _maxRetryAttempts = 3;
                _testQueueMessage.UserProperties["ConversationLockedRetryCount"] = _maxRetryAttempts - 1;
                _testQueueMessage.UserProperties["OutOfOrderRetryCount"]         = _maxRetryAttempts - 1;
                _testQueueMessage.UserProperties["PreviousMessageNotSentCount"]  = _maxRetryAttempts - 1;

                var command = new SendSmsCommand(_testOutgoingSms, _testQueueMessage);

                _mockHandler
                .Setup(m => m.HandleAsync(command, It.IsAny <CancellationToken>()))
                .ThrowsAsync(testException);

                // act
                await _sut.HandleAsync(command);

                //assert
                var existingProperties = _testQueueMessage.UserProperties.ToList().Where(i => !i.Key.Equals(retryKey));

                existingProperties.Count().Should().Be(0);
            }
            public async Task WhenCalled_ThenTheSmsIsSentUsingToTheNotificationClient()
            {
                // arrange
                var mobileNumber = Guid.NewGuid().ToString();
                var messageText  = Guid.NewGuid().ToString();
                var reference    = Guid.NewGuid().ToString();

                var message = new OutgoingSmsBuilder()
                              .WithConversation(new BotConversationBuilder().WithConversationId(reference))
                              .WithMessageText(messageText)
                              .WithParticipant(new ParticipantBuilder().WithUserId(mobileNumber));

                var command = new SendSmsCommand(message, _testQueueMessage);

                // act
                await _sut.HandleAsync(command);

                //assert
                _mockNotificationClient.Verify(m =>
                                               m.SendSms(
                                                   mobileNumber,
                                                   _testNotifyTemplateId,
                                                   It.Is <Dictionary <string, dynamic> >(i => i.ContainsKey("message") && i.ContainsValue(messageText)),
                                                   reference,
                                                   _testNotifySmsSenderId)
                                               , Times.Once);
            }
示例#8
0
        public async Task <CommandHandlingResult> Handle(SendSmsCommand command, IEventPublisher eventPublisher)
        {
            var message = await _smsRepository.GetAsync(command.Id);

            var msg = new
            {
                Phone = command.Phone.SanitizePhone(),
                command.Id,
                command.Provider,
                command.CountryCode
            };

            if (message == null)
            {
                _log.WriteInfo(nameof(SendSmsCommand), msg, $"Sms message with messageId = {command.Id} not found");
                return(CommandHandlingResult.Ok());
            }

            if (message.IsExpired(_smsSettings.SmsRetryTimeout))
            {
                await _smsRepository.DeleteAsync(message.Id, message.MessageId);

                _log.WriteInfo(nameof(SendSmsCommand), msg, "Sms message expired and has been deleted");
                return(CommandHandlingResult.Ok());
            }

            var sender = _smsSenderFactory.GetSender(command.Provider);

            _log.WriteInfo(nameof(SendSmsCommand), msg, "Sending sms");

            try
            {
                string messageId = await sender.SendSmsAsync(command.Phone, command.Message, command.CountryCode);

                if (!string.IsNullOrEmpty(messageId))
                {
                    await _smsRepository.SetMessageIdAsync(messageId, command.Id);

                    _log.WriteInfo(nameof(SendSmsCommand), new { command.Id, MessageId = messageId }, "Message has been sent");
                }
                else
                {
                    await _smsRepository.DeleteAsync(command.Id, messageId);

                    _log.WriteInfo(nameof(SendSmsCommand), new { command.Id }, "Sms message has been deleted");
                }
            }
            catch (Exception)
            {
                await _smsProviderInfoRepository.AddAsync(command.Provider, command.CountryCode, SmsDeliveryStatus.Failed);

                return(CommandHandlingResult.Fail(_smsSettings.SmsSendDelay));
            }

            return(CommandHandlingResult.Ok());
        }
示例#9
0
        public void CanSendSms_WithoutExceptions()
        {
            var smsService = Scope.Resolve <ISmsService>();
            var sms        = new SendSmsCommand
            {
                RecipientPhoneNumber = "+375293593295",
                Text = "SMS Service Test"
            };

            smsService.SendSms(sms);
        }
示例#10
0
            public async Task WhenCalled_ThenLatestConversationIsRetrievedFromtherepository()
            {
                // arrange
                var command = new SendSmsCommand(_testOutgoingSms, _testQueueMessage);

                // act
                await _sut.HandleAsync(command);

                //assert
                _mockConversationRepository.Verify(m => m.Get(_testOutgoingSms.Conversation.ConversationId), Times.Once);
            }
示例#11
0
            public async Task WhenCalled_ThenInnerHandlerIsCalled()
            {
                // arrange
                var command = new SendSmsCommand(_testOutgoingSms, _testQueueMessage);

                // act
                await _sut.HandleAsync(command);

                //assert
                _mockHandler.Verify(m => m.HandleAsync(command, It.IsAny <CancellationToken>()), Times.Once);
            }
示例#12
0
        public async Task SendSms([FromBody] SendSmsRequest request)
        {
            var message = new SendSmsCommand
            {
                Message = request.Message,
                Mobile  = request.Mobile
            };

            await _rabbitConnector.RaiseEventAsync(new SendSmsEvent
            {
                Payload    = message.ObjectSerializer(),
                RoutingKey = "RabbitMq_Consumer",
                EndpointId = SystemConstants.HostEndpointId
            });
        }
示例#13
0
        public async Task Handle(SmsProviderProcessed evt, ICommandSender commandSender)
        {
            _log.WriteInfo(nameof(SmsProviderProcessed), new { Phone = evt.Phone.SanitizePhone(), evt.Id, evt.Provider, evt.CountryCode }, "Sms processed");

            var sendSmsCommand = new SendSmsCommand
            {
                Phone       = evt.Phone,
                Message     = evt.Message,
                Provider    = evt.Provider,
                CountryCode = evt.CountryCode,
                Id          = evt.Id
            };

            commandSender.SendCommand(sendSmsCommand, "sms");
        }
            public void WhenTheNotificationClientThrowsAnException_ThenTheConversationIsNotSavedTotheConverssationRepository()
            {
                // arrange
                _mockNotificationClient.Setup(m =>
                                              m.SendSms(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <Dictionary <string, dynamic> >(), It.IsAny <string>(), It.IsAny <string>()))
                .ThrowsAsync(new Exception());

                var command = new SendSmsCommand(new OutgoingSmsBuilder(), _testQueueMessage);

                // act
                Func <Task> action = async() => await _sut.HandleAsync(command);

                //assert
                action.Should().ThrowExactly <Exception>();
                _mockConversationRepository.Verify(m => m.Save(It.IsAny <Conversation>()), Times.Never);
            }
示例#15
0
        public async Task When_UsersLimitNotEnoughToSendSms_InsufficientFundError_Should_BeReturned()
        {
            using var testServer = await CreateWithUserAsync();

            var client   = testServer.CreateClient();
            var messages = new List <SmsMessageModel>();

            for (var i = 0; i < 100; i++)
            {
                messages.Add(new SmsMessageModel("5544567788", "TEST", "TEST"));
            }

            var command  = new SendSmsCommand(Guid.NewGuid(), messages);
            var response = await client.PostAsync(ApiPath, command.ToJsonContent());

            await response.Should().BeBadRequestAsync(ErrorCodes.InsufficientFunds);
        }
示例#16
0
            public async Task WhenTheInnerHandlerThrowsAHandledException_ThenTheDelayIsLogged(Type exceptionType)
            {
                // arrange
                var errorMessage  = Guid.NewGuid().ToString();
                var testException = (Exception)Activator.CreateInstance(exceptionType, errorMessage);

                var command = new SendSmsCommand(_testOutgoingSms, _testQueueMessage);

                _mockHandler
                .Setup(m => m.HandleAsync(command, It.IsAny <CancellationToken>()))
                .ThrowsAsync(testException);

                // act
                await _sut.HandleAsync(command);

                //assert
                _mockLogger.Verify(m => m.Log(LogLevel.Information, 0, It.Is <FormattedLogValues>(l => l[0].Value.Equals($"{testException.Message} Delaying the processing for this message.")), null, It.IsAny <Func <object, Exception, string> >()), Times.Once);
            }
示例#17
0
            public void WhenTheInnerHandlerThrowsAnUnhandledException_ThenExceptionIsPropogated()
            {
                // arrange
                var errorMessage  = Guid.NewGuid().ToString();
                var testException = new Exception(errorMessage);

                var command = new SendSmsCommand(_testOutgoingSms, _testQueueMessage);

                _mockHandler
                .Setup(m => m.HandleAsync(command, It.IsAny <CancellationToken>()))
                .ThrowsAsync(testException);

                // act
                Func <Task> action = async() => await _sut.HandleAsync(command);

                //assert
                action.Should().ThrowExactly <Exception>().WithMessage(errorMessage);
            }
示例#18
0
            public async Task WhenTheInnerHandlerThrowsAHandledException_ThenADelayedMessageIsSentToTheQueue(Type exceptionType, string retryKey)
            {
                // arrange
                var errorMessage  = Guid.NewGuid().ToString();
                var testException = (Exception)Activator.CreateInstance(exceptionType, errorMessage);

                var command = new SendSmsCommand(_testOutgoingSms, _testQueueMessage);

                _mockHandler
                .Setup(m => m.HandleAsync(command, It.IsAny <CancellationToken>()))
                .ThrowsAsync(testException);

                // act
                await _sut.HandleAsync(command);

                //assert
                _mockQueueClient.Verify(m => m.SendAsync(It.Is <Message>((qm) => ((int)qm.UserProperties[retryKey]) == 1)), Times.Once);
            }
示例#19
0
        public async Task Handle(SmsMessageDeliveryFailed evt, ICommandSender commandSender)
        {
            _log.WriteInfo(nameof(SmsMessageDeliveryFailed), new
            {
                Phone = evt.Message.Phone.SanitizePhone(), evt.Message.Id, evt.Message.Provider, evt.Message.CountryCode
            }, $"Retrying sms delivery. Sending using {evt.Message.Provider.ToString()}, country code: {evt.Message.CountryCode}");

            var sendSmsCommand = new SendSmsCommand
            {
                Phone       = evt.Message.Phone,
                Message     = evt.Message.Message,
                Provider    = evt.Message.Provider,
                CountryCode = evt.Message.CountryCode,
                Id          = evt.Message.Id
            };

            commandSender.SendCommand(sendSmsCommand, "sms");
        }
示例#20
0
            public async Task WhenTheConversationHasAlreadyBeenStartedAndTheCommandIsInOrder_ThenTheInnerHandlerIsCalled()
            {
                // arrange
                Conversation lastConversation = new ConversationBuilder()
                                                .WithId(_testOutgoingSms.Conversation.ConversationId)
                                                .WithTurnId(2);

                _testOutgoingSms.Conversation.TurnId = lastConversation.TurnId + 1;

                var command = new SendSmsCommand(_testOutgoingSms, _testQueueMessage);

                _mockConversationRepository
                .Setup(m => m.Get(_testOutgoingSms.Conversation.ConversationId))
                .ReturnsAsync(lastConversation);

                // act
                await _sut.HandleAsync(command);

                //assert
                _mockHandler.Verify(m => m.HandleAsync(command, It.IsAny <CancellationToken>()), Times.Once);
            }
        private void Handle(SmsNotificationJobContext context, SmsCodeCreated smsCodeCreated)
        {
            var profile = VerifyProfile(context, smsCodeCreated.UserId);

            if (profile == null)
            {
                return;
            }
            if (!profile.SmsConfirmationEnabled)
            {
                Logger.Error("Sms code was created for user with sms confirmation feature disabled.");
                return;
            }
            var sms = new SendSmsCommand
            {
                RecipientPhoneNumber = profile.PhoneNumber,
                Text = string.Format(SmsMessages.SecurityCode, smsCodeCreated.Code)
            };

            context.SmsService.SendSms(sms);
        }
示例#22
0
            public async Task WhenTheTurnIdIsThesameAsTheCurentOne_ThenTheInnerHandlerIsNotCalled()
            {
                // arrange
                Conversation lastConversation = new ConversationBuilder()
                                                .WithId(_testOutgoingSms.Conversation.ConversationId)
                                                .WithTurnId(2);

                _testOutgoingSms.Conversation.TurnId = lastConversation.TurnId;

                var command = new SendSmsCommand(_testOutgoingSms, _testQueueMessage);

                _mockConversationRepository
                .Setup(m => m.Get(_testOutgoingSms.Conversation.ConversationId))
                .ReturnsAsync(lastConversation);

                // act
                await _sut.HandleAsync(command);

                //assert
                _mockHandler.Verify(m => m.HandleAsync(command, It.IsAny <CancellationToken>()), Times.Never);
            }
示例#23
0
            public void WhenTheTurnIdIsOutOfOrder_ThenAnOutOfOrderExceptionIscalled()
            {
                // arrange
                Conversation lastConversation = new ConversationBuilder()
                                                .WithId(_testOutgoingSms.Conversation.ConversationId)
                                                .WithTurnId(3);

                _testOutgoingSms.Conversation.TurnId = lastConversation.TurnId + 2;

                var command = new SendSmsCommand(_testOutgoingSms, _testQueueMessage);

                _mockConversationRepository
                .Setup(m => m.Get(_testOutgoingSms.Conversation.ConversationId))
                .ReturnsAsync(lastConversation);

                // act
                Func <Task> action = async() => await _sut.HandleAsync(command);

                //assert
                action.Should().ThrowExactly <OutOfOrderException>().WithMessage($"Message for conversation {_testOutgoingSms.Conversation.ConversationId} processed out of order.  Expected turnId {lastConversation.TurnId + 1} but received turnId {command.Message.Conversation.TurnId} with activityId {command.Message.Conversation.ActivityId}");
            }
示例#24
0
            public void WhenTheTurnIdIsOutOfOrder_ThenTheInnerHandlerIsNotCalled()
            {
                // arrange
                Conversation lastConversation = new ConversationBuilder()
                                                .WithId(_testOutgoingSms.Conversation.ConversationId)
                                                .WithTurnId(3);

                _testOutgoingSms.Conversation.TurnId = lastConversation.TurnId + 2;

                var command = new SendSmsCommand(_testOutgoingSms, _testQueueMessage);

                _mockConversationRepository
                .Setup(m => m.Get(_testOutgoingSms.Conversation.ConversationId))
                .ReturnsAsync(lastConversation);

                // act
                Func <Task> action = async() => await _sut.HandleAsync(command);

                action.Invoke();

                //assert
                _mockHandler.Verify(m => m.HandleAsync(It.IsAny <SendSmsCommand>(), It.IsAny <CancellationToken>()), Times.Never);
            }
示例#25
0
 public void SendSms(SendSmsCommand command)
 {
     EnsureIsValid(command);
     try
     {
         if (_settings.UseLogger)
         {
             var smsModel = new SmsModel
             {
                 From = _settings.OutboundPhoneNumber,
                 Text = command.Text,
                 To   = command.RecipientPhoneNumber
             };
             _deps.SmsLogger.Log(smsModel);
         }
         var client = _deps.TwilioClientFactory.Create();
         client.SendSmsMessage(_settings.OutboundPhoneNumber, command.RecipientPhoneNumber, command.Text);
     }
     catch (Exception ex)
     {
         throw new ServiceException("Can't send sms.", ex);
     }
 }
示例#26
0
 public Result SendSms(SendSmsCommand sendSmsCommand)
 {
     throw new NotImplementedException();
 }
        private void Handle(SmsNotificationJobContext context, TransactionProcessedEvent smsEvent)
        {
            var transaction = context.ProcessingService.GetCardTransaction(new IdentityQuery <Guid>(smsEvent.TransactionId));

            if (transaction == null)
            {
                return;
            }
            if (transaction.Status == ProcessStatusModel.Pending)
            {
                return;
            }
            var account = context.CardAccountService.GetCardAccountBrief(new IdentityQuery <string>(transaction.AccountNo));

            if (account == null)
            {
                Logger.Info("Couldn't find account for card transaction #{0}.", smsEvent.TransactionId);
                return;
            }
            var profile = VerifyProfile(context, account.Owner.UserId);

            if (profile == null || !profile.SmsNotificationEnabled)
            {
                return;
            }
            var sms = new SendSmsCommand {
                RecipientPhoneNumber = profile.PhoneNumber
            };
            var secureCardNo = string.Format(
                "{0}****{1}",
                new string(transaction.CardNo.Take(8).ToArray()),
                new string(transaction.CardNo.Skip(12).ToArray()));

            if (transaction.Status == ProcessStatusModel.Failed)
            {
                var message = string.Format(
                    SmsMessages.CardError,
                    secureCardNo,
                    string.Format("{0:F2} {1}", transaction.TransactionAmount, transaction.Currency.ISOName),
                    transaction.Location,
                    TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, _timezone),
                    string.Format("{0:F2} {1}", account.Balance, account.Currency.ISOName));
                sms.Text = message;
                context.SmsService.SendSms(sms);
                return;
            }
            if (transaction.TransactionAmount < 0)
            {
                var message = string.Format(
                    SmsMessages.CardWithdrawal,
                    secureCardNo,
                    string.Format("{0:F2} {1}", -transaction.TransactionAmount, transaction.Currency.ISOName),
                    transaction.Location,
                    TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, _timezone),
                    string.Format("{0:F2} {1}", account.Balance, account.Currency.ISOName));
                sms.Text = message;
                context.SmsService.SendSms(sms);
            }
            else
            {
                var message = string.Format(
                    SmsMessages.CardDeposit,
                    secureCardNo,
                    string.Format("{0:F2} {1}", transaction.TransactionAmount, transaction.Currency.ISOName),
                    transaction.Location,
                    TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, _timezone),
                    string.Format("{0:F2} {1}", account.Balance, account.Currency.ISOName));
                sms.Text = message;
                context.SmsService.SendSms(sms);
            }
        }
示例#28
0
        public async Task <IActionResult> SendSmsAsync([FromBody, Required] SendSmsCommand command)
        {
            await _commandProcessor.SendAsync(command);

            return(Accepted());
        }