Exemplo n.º 1
0
        public async Task CreateAccountUseCreditDestroyAccount()
        {
            Init();
            IRepository<string, DbUserAccount> userAccountRespository = _UserAccountRepositoryFactory.Create();

            using (DbUserAccountContext ctx = new DbUserAccountContext(dbOptions))
            {
                ctx.Database.ExecuteSqlCommand("DELETE FROM DbUserAccount");
                ctx.Database.ExecuteSqlCommand("DELETE FROM DbUserAccountCreditBalance");
            }

            string username = "******";
            string password = "******";

            // Make sure that LoadAsync retursn null for an account that doesn't exist yet.
            DbUserAccount accountThatShouldNotExist = await userAccountRespository.LoadAsync(username);
            Assert.Null(accountThatShouldNotExist);

            // Create an add a new account to the database
            DbUserAccount newAccount = userAccountController.Create(username, password);
            newAccount.CreditLimit = 1d;

            await userAccountRespository.AddAsync(newAccount);

            // Load that account back in
            DbUserAccount reloadedAccount = await userAccountRespository.LoadAsync(username);
            Assert.NotNull(reloadedAccount);

            // Try to use half of the credit limit
            double credit = await userAccountController.TryGetCreditAsync(reloadedAccount, 0.5);
            Assert.Equal(credit, 0.5d);

            // Try to use 100 times the credit limit of 1, only to receive ~.5 back
            // (you'll get a tiny amount more as the consumed credit has decayed with time)
            double moreCredit = await userAccountController.TryGetCreditAsync(reloadedAccount, 1000);
            Assert.InRange(moreCredit, 0.5d, 0.51d);

            // Clean up
            using (DbUserAccountContext context = new DbUserAccountContext(dbOptions))
            {
                DbUserAccount account =
                    context.DbUserAccounts.FirstOrDefault(a => a.UsernameOrAccountId == username);

                Assert.NotNull(account);
                
                if (account != null)
                    context.DbUserAccounts.Remove(account);

                await context.SaveChangesAsync();

                DbUserAccountCreditBalance balance =
                    context.DbUserAccountCreditBalances.FirstOrDefault(a => a.DbUserAccountId == username);
                if (balance != null)
                {
                    context.DbUserAccountCreditBalances.Remove(balance);
                    await context.SaveChangesAsync();
                }
            }

        }
Exemplo n.º 2
0
 public async Task AddAsync(DbUserAccount itemToAdd, CancellationToken cancellationToken = default(CancellationToken))
 {
     _context.DbUserAccounts.Add(itemToAdd);
     await _context.SaveChangesAsync(cancellationToken);
 }
Exemplo n.º 3
0
        public override async Task <double> TryGetCreditAsync(
            DbUserAccount userAccount,
            double amountRequested,
            DateTime?timeOfRequestUtc           = null,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            if (Double.IsNaN(amountRequested) || amountRequested <= 0)
            {
                // You can't request a negative amount and requesting nothing is free
                return(0);
            }

            DateTime timeOfRequestOrNowUtc = timeOfRequestUtc ?? DateTime.Now;

            double creditRetrieved = 0;

            using (var context = new DbUserAccountContext(DbOptions))
            {
                using (var dbContextTransaction = await context.Database.BeginTransactionAsync(cancellationToken))
                {
                    bool rolledBackDueToConcurrencyException = false;
                    do
                    {
                        try
                        {
                            DbUserAccountCreditBalance balance = await
                                                                 context.DbUserAccountCreditBalances.Where(b => b.DbUserAccountId == userAccount.DbUserAccountId)
                                                                 .FirstOrDefaultAsync(cancellationToken: cancellationToken);

                            if (balance == null)
                            {
                                creditRetrieved = Math.Min(amountRequested, userAccount.CreditLimit);
                                double amountRemaining = userAccount.CreditLimit - creditRetrieved;
                                context.DbUserAccountCreditBalances.Add(
                                    new DbUserAccountCreditBalance()
                                {
                                    DbUserAccountId = userAccount.DbUserAccountId,
                                    ConsumedCreditsLastUpdatedUtc = timeOfRequestOrNowUtc,
                                    ConsumedCreditsLastValue      = amountRemaining
                                });
                            }
                            else
                            {
                                double amountAvailable = Math.Max(0, userAccount.CreditLimit -
                                                                  DecayingDouble.Decay(balance.ConsumedCreditsLastValue, userAccount.CreditHalfLife,
                                                                                       balance.ConsumedCreditsLastUpdatedUtc, timeOfRequestOrNowUtc));
                                if (amountAvailable > 0)
                                {
                                    creditRetrieved = Math.Min(amountRequested, amountAvailable);
                                }
                                double amountRemaining = amountAvailable - creditRetrieved;
                                balance.ConsumedCreditsLastValue      = amountRemaining;
                                balance.ConsumedCreditsLastUpdatedUtc = timeOfRequestOrNowUtc;
                            }

                            await context.SaveChangesAsync(cancellationToken);

                            dbContextTransaction.Commit();
                        }
                        catch (DbUpdateConcurrencyException)
                        {
                            dbContextTransaction.Rollback();
                            rolledBackDueToConcurrencyException = true;
                        }
                    } while (rolledBackDueToConcurrencyException);
                }
            }

            return(creditRetrieved);
        }