예제 #1
0
        public void ReturnsTheCurrentDateTime()
        {
            var provider = new NowProvider();
            var realNow  = DateTime.Now;
            var provided = provider.Now;

            // make sure they're at least pretty close
            Assert.IsTrue(Math.Abs(realNow.Ticks - provided.Ticks) < 1000);
        }
        public void Fails_No_Amount()
        {
            var request     = new ProcessPaymentRequest();
            var nowProvider = new NowProvider();
            var validator   = new ProcessPaymentValidator(nowProvider);
            var failures    = validator.ShouldHaveValidationErrorFor(r => r.Amount, request);

            Assert.AreEqual(1, failures.Count());
            Assert.AreEqual("Amount must be greater than 0", failures.First().ErrorMessage);
        }
        public void Fails_No_Owner()
        {
            var request     = new ProcessPaymentRequest();
            var nowProvider = new NowProvider();
            var validator   = new ProcessPaymentValidator(nowProvider);
            var failures    = validator.ShouldHaveValidationErrorFor(r => r.Owner, request);

            Assert.AreEqual(1, failures.Count());
            Assert.AreEqual("Owner required", failures.First().ErrorMessage);
        }
        public void Fails_No_Expiry()
        {
            var request     = new ProcessPaymentRequest();
            var nowProvider = new NowProvider();
            var validator   = new ProcessPaymentValidator(nowProvider);
            var failures    = validator.ShouldHaveValidationErrorFor(r => r.Expiry, request);

            Assert.IsTrue(failures.Any());
            Assert.AreEqual("Expiry required", failures.First().ErrorMessage);
        }
        public void Passes_CVV_3_Digit()
        {
            var request = new ProcessPaymentRequest
            {
                CVV = "123"
            };
            var nowProvider = new NowProvider();
            var validator   = new ProcessPaymentValidator(nowProvider);

            validator.ShouldNotHaveValidationErrorFor(r => r.CVV, request);
        }
        public void Passes_Positive_Amount()
        {
            var request = new ProcessPaymentRequest
            {
                Amount = 1
            };
            var nowProvider = new NowProvider();
            var validator   = new ProcessPaymentValidator(nowProvider);

            validator.ShouldNotHaveValidationErrorFor(r => r.Amount, request);
        }
        public void Passes_Valid_Card_Number()
        {
            var request = new ProcessPaymentRequest
            {
                CardNumber = "4111111111111111"
            };
            var nowProvider = new NowProvider();
            var validator   = new ProcessPaymentValidator(nowProvider);

            validator.ShouldNotHaveValidationErrorFor(r => r.CardNumber, request);
        }
        public void Passes_Owner()
        {
            var request = new ProcessPaymentRequest
            {
                Owner = "Owner"
            };
            var nowProvider = new NowProvider();
            var validator   = new ProcessPaymentValidator(nowProvider);

            validator.ShouldNotHaveValidationErrorFor(r => r.Owner, request);
        }
        public void Passes_Currency_Code()
        {
            var request = new ProcessPaymentRequest
            {
                Currency = "GBP"
            };
            var nowProvider = new NowProvider();
            var validator   = new ProcessPaymentValidator(nowProvider);

            validator.ShouldNotHaveValidationErrorFor(r => r.Currency, request);
        }
예제 #10
0
        public async Task Return_DateTime_Now_If_No_Value_Set()
        {
            var provider = new NowProvider();

            var firstGet = provider.Now;
            await Task.Delay(10);

            var secondGet = provider.Now;

            Assert.AreNotEqual(firstGet, secondGet);
            Assert.AreNotEqual(DateTime.MinValue, firstGet);
        }
        public void Fails_Currency_Not_Supported()
        {
            var request = new ProcessPaymentRequest
            {
                Currency = "definitely not in the list"
            };
            var nowProvider = new NowProvider();
            var validator   = new ProcessPaymentValidator(nowProvider);
            var failures    = validator.ShouldHaveValidationErrorFor(r => r.Currency, request);

            Assert.AreEqual(1, failures.Count());
            Assert.AreEqual("ISO 4217 Currency code not recognised", failures.First().ErrorMessage);
        }
        public void Fails_CVV_Letters(char letter)
        {
            var request = new ProcessPaymentRequest
            {
                CVV = $"1{letter}3"
            };
            var nowProvider = new NowProvider();
            var validator   = new ProcessPaymentValidator(nowProvider);
            var failures    = validator.ShouldHaveValidationErrorFor(r => r.CVV, request);

            Assert.AreEqual(1, failures.Count());
            Assert.AreEqual("CVV must not contain letters or symbols", failures.First().ErrorMessage);
        }
        public void Fails_CVV_4_Digits()
        {
            var request = new ProcessPaymentRequest
            {
                CVV = "1234"
            };
            var nowProvider = new NowProvider();
            var validator   = new ProcessPaymentValidator(nowProvider);
            var failures    = validator.ShouldHaveValidationErrorFor(r => r.CVV, request);

            Assert.AreEqual(1, failures.Count());
            Assert.AreEqual("CVV must be 3 characters long", failures.First().ErrorMessage);
        }
        public void Fails_Invalid_Card_Number(string cardNumber)
        {
            var request = new ProcessPaymentRequest
            {
                CardNumber = cardNumber
            };
            var nowProvider = new NowProvider();
            var validator   = new ProcessPaymentValidator(nowProvider);
            var failures    = validator.ShouldHaveValidationErrorFor(r => r.CardNumber, request);

            Assert.AreEqual(1, failures.Count());
            Assert.AreEqual("Card number invalid", failures.First().ErrorMessage);
        }
        public void Passes_Same_Month_Expiry()
        {
            var testNow = new DateTime(2021, 01, 31);

            var request = new ProcessPaymentRequest
            {
                Expiry = new MonthYear {
                    Year = testNow.Year, Month = testNow.Month
                }                                                                     // date should be last day of 2 months into the future
            };
            var nowProvider = new NowProvider();
            var validator   = new ProcessPaymentValidator(nowProvider);

            validator.ShouldNotHaveValidationErrorFor(r => r.Expiry, request);
        }
예제 #16
0
        private TimeWarpAuthenticationManager(IAccountRepository accounts)
        {
            _accounts = accounts;
            _log      = LogManager.GetLogger(GetType());
            var sessionTimeOutMinutes = ConfigurationManager.AppSettings["SessionTimeOutMinutes"];

            SessionTimeOut              = TimeSpan.FromMinutes(int.Parse(sessionTimeOutMinutes));
            TimeOutProvider             = new NowProvider();
            SessionIdProvider           = new SessionIdProvider();
            HeaderValueProvider         = new HttpContextHeaderValueProvider();
            AccountOperatorProvider     = new AccountIdsProvider();
            _authenticationSessionCache = new Dictionary <string, AuthenticationSession>();

            _log.Info("TimeWarpAuthenticationManager Instantiated");
        }
        public void Passes_In_Future_Expiry()
        {
            var testNow    = new DateTime(2021, 01, 01);
            var expiryDate = testNow.AddMonths(3).AddDays(-1);

            var request = new ProcessPaymentRequest
            {
                Expiry = new MonthYear {
                    Year = expiryDate.Year, Month = expiryDate.Month
                }                                                                           // date should be last day of 2 months into the future
            };
            var nowProvider = new NowProvider();
            var validator   = new ProcessPaymentValidator(nowProvider);

            validator.ShouldNotHaveValidationErrorFor(r => r.Expiry, request);
        }
예제 #18
0
        public async Task Holds_For_All_URIs_With_Same_Domain()
        {
            var window      = TimeSpan.FromMilliseconds(1000);
            var nowProvider = new NowProvider(new DateTime(2020, 01, 01));
            var limiter     = new RollingWindowRateLimiter(window, 1, nowProvider);

            var firstURI  = new Uri("http://domain.com/something");
            var secondURI = new Uri("http://domain.com/something-else");

            var stopwatch = new Stopwatch();
            await limiter.HoldIfRequired(firstURI);

            stopwatch.Start();
            await limiter.HoldIfRequired(secondURI);

            Assert.IsTrue(stopwatch.ElapsedMilliseconds >= 1000);
        }
        public async Task Returns_Error_Response_When_Cache_Already_Contains_Key()
        {
            const string  CARD_NUMBER = "4111111111111111";
            const string  CVV         = "123";
            const string  CURRENCY    = "GBP";
            const string  OWNER       = "owner";
            const decimal AMOUNT      = .1m;
            var           EXPIRY      = new MonthYear {
                Year = 2021, Month = 01
            };

            var testNow     = new DateTime(2021, 02, 01);
            var nowProvider = new NowProvider(testNow);

            var request = new ProcessPaymentRequest
            {
                CardNumber = CARD_NUMBER,
                Amount     = AMOUNT,
                Currency   = CURRENCY,
                CVV        = CVV,
                Expiry     = EXPIRY,
                Owner      = OWNER
            };

            var acqBankMock     = new Mock <IAcquiringBank>();
            var memoryCacheMock = new Mock <IMemoryCache>();

            memoryCacheMock
            .Setup(mock => mock.TryGetValue(It.IsAny <string>(), out It.Ref <object> .IsAny))
            .Returns(true);

            using var context = Setup.CreateContext();

            var handler = new ProcessPaymentHandler(
                acqBankMock.Object,
                nowProvider,
                memoryCacheMock.Object,
                _logger,
                _cachingOptions,
                context);

            var result = (await handler.Handle(request, CancellationToken.None)).ErrorOrDefault;

            Assert.AreEqual(HttpStatusCode.TooManyRequests, result.StatusCode);
        }
        public void Fails_No_Expiry_Month()
        {
            var testNow    = new DateTime(2021, 01, 01);
            var expiryDate = testNow.AddSeconds(-1);

            var request = new ProcessPaymentRequest
            {
                Expiry = new MonthYear {
                    Year = expiryDate.Year, Month = 0
                }                                                            // a passed date should not be valid
            };
            var nowProvider = new NowProvider(testNow);
            var validator   = new ProcessPaymentValidator(nowProvider);
            var failures    = validator.ShouldHaveValidationErrorFor(r => r.Expiry.Month, request);

            Assert.AreEqual(1, failures.Count());
            Assert.AreEqual("Expiry month must be between 1 and 12", failures.First().ErrorMessage);
        }
예제 #21
0
        public async Task Does_Not_Hold_If_Domain_New()
        {
            var window      = TimeSpan.MaxValue;
            var nowProvider = new NowProvider(new DateTime(2020, 01, 01));
            var limiter     = new RollingWindowRateLimiter(window, 1, nowProvider);

            var uri = new Uri("http://domain.com/something");

            var waitTask  = limiter.HoldIfRequired(uri);
            var stopwatch = new Stopwatch();

            stopwatch.Start();

            while (!waitTask.IsCompleted)
            {
                if (stopwatch.ElapsedMilliseconds > 1000)
                {
                    Assert.Fail("Took too long");
                }
            }

            await waitTask;
        }
        public async Task Unsuccesful_Bank_Result_Does_Not_Throw()
        {
            const int     RETURNED_PAYMENT_ID = 1;
            const string  CARD_NUMBER         = "4111111111111111";
            const string  CVV      = "123";
            const string  CURRENCY = "GBP";
            const string  OWNER    = "owner";
            const decimal AMOUNT   = .1m;
            var           EXPIRY   = new MonthYear {
                Year = 2021, Month = 01
            };

            var testNow     = new DateTime(2021, 02, 01);
            var nowProvider = new NowProvider(testNow);

            var request = new ProcessPaymentRequest
            {
                CardNumber = CARD_NUMBER,
                Amount     = AMOUNT,
                Currency   = CURRENCY,
                CVV        = CVV,
                Expiry     = EXPIRY,
                Owner      = OWNER
            };

            using var context = Setup.CreateContext();

            var acqBankMock = new Mock <IAcquiringBank>();

            acqBankMock
            .Setup(mock => mock.SendPayment(It.IsAny <AcquiringBankRequest>()))
            .ReturnsAsync(new AcquiringBankResponse
            {
                Status    = AcquiringBankResponseStatus.Acquiring_Bank_Unreachable,
                PaymentId = RETURNED_PAYMENT_ID
            });

            var memoryCacheMock = new Mock <IMemoryCache>();
            var cacheEntryMock  = new Mock <ICacheEntry>();

            memoryCacheMock
            .Setup(mock => mock.TryGetValue(It.IsAny <string>(), out It.Ref <object> .IsAny))
            .Returns(false);

            memoryCacheMock
            .Setup(mock => mock.CreateEntry(It.IsAny <object>()))
            .Returns(cacheEntryMock.Object);

            // use mock of acqbank to ensure we get a failure here
            var handler = new ProcessPaymentHandler(
                acqBankMock.Object,
                nowProvider,
                memoryCacheMock.Object,
                _logger,
                _cachingOptions,
                context);
            var result = (await handler.Handle(request, CancellationToken.None)).SuccessOrDefault;

            // ensure payment is still saved in failed state
            var foundPayment = context.ProcessedPayments.Find(result.PaymentId);

            Assert.AreEqual(RETURNED_PAYMENT_ID, result.PaymentId);
            Assert.IsFalse(result.Success);

            Assert.AreEqual("************1111", foundPayment.CardNumber);
            Assert.AreEqual("***", foundPayment.CVV);
            Assert.AreEqual(AMOUNT, foundPayment.Amount);
            Assert.AreEqual(CURRENCY, foundPayment.Currency);
            Assert.AreEqual(OWNER, foundPayment.Owner);

            Assert.AreEqual(EXPIRY.Year, foundPayment.Expiry.Year);
            Assert.AreEqual(EXPIRY.Month, foundPayment.Expiry.Month);
        }
        public async Task Stores_Masked_Card_Details()
        {
            const int     RETURNED_PAYMENT_ID = 1;
            const string  CARD_NUMBER         = "4111111111111111";
            const string  CVV      = "123";
            const string  CURRENCY = "GBP";
            const string  OWNER    = "owner";
            const decimal AMOUNT   = .1m;
            var           EXPIRY   = new MonthYear {
                Year = 2021, Month = 01
            };

            var testNow     = new DateTime(2021, 02, 01);
            var nowProvider = new NowProvider(testNow);

            var request = new ProcessPaymentRequest
            {
                CardNumber = CARD_NUMBER,
                Amount     = AMOUNT,
                Currency   = CURRENCY,
                CVV        = CVV,
                Expiry     = EXPIRY,
                Owner      = OWNER
            };

            var acqBankMock = new Mock <IAcquiringBank>();

            acqBankMock
            .Setup(mock => mock.SendPayment(It.IsAny <AcquiringBankRequest>()))
            .ReturnsAsync(new AcquiringBankResponse
            {
                Status    = AcquiringBankResponseStatus.Success,
                PaymentId = RETURNED_PAYMENT_ID
            });

            var memoryCacheMock = new Mock <IMemoryCache>();
            var cacheEntryMock  = new Mock <ICacheEntry>();

            memoryCacheMock
            .Setup(mock => mock.TryGetValue(It.IsAny <string>(), out It.Ref <object> .IsAny))
            .Returns(false);

            memoryCacheMock
            .Setup(mock => mock.CreateEntry(It.IsAny <object>()))
            .Returns(cacheEntryMock.Object);

            using var context = Setup.CreateContext();

            var handler = new ProcessPaymentHandler(
                acqBankMock.Object,
                nowProvider,
                memoryCacheMock.Object,
                _logger,
                _cachingOptions,
                context);
            var result = (await handler.Handle(request, CancellationToken.None)).SuccessOrDefault;

            Assert.IsTrue(result.Success);

            // assert that a record is in the db for this payment id,
            var foundPayment = context.ProcessedPayments.Find(result.PaymentId);

            // should be masked
            Assert.AreEqual("************1111", foundPayment.CardNumber);
            Assert.AreEqual("***", foundPayment.CVV);
            Assert.AreEqual(AMOUNT, foundPayment.Amount);
            Assert.AreEqual(CURRENCY, foundPayment.Currency);
            Assert.AreEqual(OWNER, foundPayment.Owner);

            Assert.AreEqual(EXPIRY.Year, foundPayment.Expiry.Year);
            Assert.AreEqual(EXPIRY.Month, foundPayment.Expiry.Month);
        }
예제 #24
0
        public void ReturnsASetDate()
        {
            var provider = new NowProvider();

            Assert.AreNotEqual(DateTime.MinValue, provider.Now);
        }
예제 #25
0
        public void Return_Value_Set()
        {
            var provider = new NowProvider(new DateTime(2020, 01, 01));

            Assert.AreEqual(new DateTime(2020, 01, 01), provider.Now);
        }
        public async Task Adds_Key_To_Cache()
        {
            const string  GENERATED_REQUEST_KEY = "1v9ESIpTOJ1czY9SZW5oWf2DiRWrNOB4kHdPFODIYjI=";
            const int     RETURNED_PAYMENT_ID   = 1;
            const string  CARD_NUMBER           = "4111111111111111";
            const string  CVV      = "123";
            const string  CURRENCY = "GBP";
            const string  OWNER    = "owner";
            const decimal AMOUNT   = .1m;
            var           EXPIRY   = new MonthYear {
                Year = 2021, Month = 01
            };

            var testNow     = new DateTime(2021, 02, 01);
            var nowProvider = new NowProvider(testNow);

            var request = new ProcessPaymentRequest
            {
                CardNumber = CARD_NUMBER,
                Amount     = AMOUNT,
                Currency   = CURRENCY,
                CVV        = CVV,
                Expiry     = EXPIRY,
                Owner      = OWNER
            };

            var acqBankMock = new Mock <IAcquiringBank>();

            acqBankMock
            .Setup(mock => mock.SendPayment(It.IsAny <AcquiringBankRequest>()))
            .ReturnsAsync(new AcquiringBankResponse
            {
                Status    = AcquiringBankResponseStatus.Success,
                PaymentId = RETURNED_PAYMENT_ID
            });

            var memoryCacheMock = new Mock <IMemoryCache>();
            var cacheEntryMock  = new Mock <ICacheEntry>();

            memoryCacheMock
            .Setup(mock => mock.TryGetValue(It.IsAny <string>(), out It.Ref <object> .IsAny))
            .Returns(false);

            memoryCacheMock
            .Setup(mock => mock.CreateEntry(It.IsAny <object>()))
            .Returns(cacheEntryMock.Object);

            using var context = Setup.CreateContext();

            var handler = new ProcessPaymentHandler(
                acqBankMock.Object,
                nowProvider,
                memoryCacheMock.Object,
                _logger,
                _cachingOptions,
                context);
            var result = await handler.Handle(request, CancellationToken.None);

            memoryCacheMock.Verify(
                mock => mock.CreateEntry(GENERATED_REQUEST_KEY),
                Times.Once);
        }