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); }
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); }
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); }
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); }
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); }
public void ReturnsASetDate() { var provider = new NowProvider(); Assert.AreNotEqual(DateTime.MinValue, provider.Now); }
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); }