public async Task DeleteFriendInvite()
        {
            using var contextFactory        = new TestTriviaGameContextFactory();
            using TriviaRankContext context = contextFactory.CreateContext();

            var insertedPlayer1 = new Player
            {
                Username  = "******",
                Password  = "******",
                Birthday  = DateTime.Now,
                Points    = 100,
                FirstName = "Bart",
                LastName  = "Simpson"
            };
            var insertedPlayer2 = new Player
            {
                Username  = "******",
                Password  = "******",
                Birthday  = DateTime.Now,
                Points    = 200,
                FirstName = "Milhouse",
                LastName  = "Vanhouten"
            };
            await context.Players.AddAsync(insertedPlayer1);

            await context.Players.AddAsync(insertedPlayer2);

            context.SaveChanges();
            var repo = new OutboxRepository(context);
            await repo.createFriendInvite(insertedPlayer1.Username, insertedPlayer2.Username);

            await repo.deleteFriendInvite(insertedPlayer1.Username, insertedPlayer2.Username);

            Assert.Empty((await repo.getFriendInvites(insertedPlayer2.Id)).Where(p => p.Id == insertedPlayer1.Id));
        }
Exemple #2
0
        public OutboxRepositoryShould()
        {
            var options = new DbContextOptionsBuilder <OutboxConsumerDbContext>().UseInMemoryDatabase(Guid.NewGuid().ToString()).Options;

            dbContext  = new OutboxConsumerDbContext(options);
            repository = new OutboxRepository(dbContext);
        }
        public async Task ReadMessagesToProcess_should_return_empty_collection_if_no_data_available()
        {
            var dbCtx      = NSubstitute.Substitute.For <IDbContext>();
            var serializer = NSubstitute.Substitute.For <ISerializer>();
            var sut        = new OutboxRepository(dbCtx, serializer);

            var result = await sut.ReadMessagesToProcess();

            result.Should().NotBeNull().And.BeEmpty();
        }
Exemple #4
0
        public BusSubscriptionsWithOutboxShould()
        {
            var logger = Substitute.For <ILogger <BusSubscriptionsWithOutbox> >();

            outboxRepository = Substitute.For <OutboxRepository>(new object[] { null });
            timer            = new RepeatingTimer(new TimerConfiguration()
            {
                DueSeconds = -1, PeriodSeconds = -1
            });
            busSubscriptions = new BusSubscriptionsWithOutbox(logger, outboxRepository, timer);
        }
        public async Task CheckCreateValidGameInvite()
        {
            using var contextFactory        = new TestTriviaGameContextFactory();
            using TriviaRankContext context = contextFactory.CreateContext();

            var insertedPlayer1 = new Player
            {
                Username  = "******",
                Password  = "******",
                Birthday  = DateTime.Now,
                Points    = 100,
                FirstName = "Bart",
                LastName  = "Simpson"
            };
            var insertedPlayer2 = new Player
            {
                Username  = "******",
                Password  = "******",
                Birthday  = DateTime.Now,
                Points    = 200,
                FirstName = "Milhouse",
                LastName  = "Vanhouten"
            };
            await context.Players.AddAsync(insertedPlayer1);

            await context.Players.AddAsync(insertedPlayer2);

            context.SaveChanges();
            var game1 = new Game
            {
                GameName       = "new game 1",
                OwnerId        = insertedPlayer1.Id,
                StartDate      = DateTimeOffset.Now,
                EndDate        = DateTimeOffset.Now,
                GameMode       = true,
                TotalQuestions = 10,
                IsPublic       = true
            };
            await context.Games.AddAsync(game1);

            context.SaveChanges();

            var repo = new OutboxRepository(context);
            await repo.createGameInvite(game1.Id, insertedPlayer2.Id);

            var invitedGame = (await repo.getGameInvites(insertedPlayer2.Id)).FirstOrDefault();

            Assert.Equal(game1.Id, invitedGame.Id);
        }
        protected virtual async Task UpdateProcessedItemsInternal(
            OutboxProcessingResults <TUniqueIdentifier> results,
            OutboxProcessingOptions options
            )
        {
            //Update & store the state for all Items Processed (e.g. Successful, Attempted, Failed, etc.)!
            var processedItems = results.GetAllProcessedItems();

            options.LogDebugCallback?.Invoke($"Starting to update the Outbox for [{processedItems.Count}] items...");

            if (processedItems.Count > 0)
            {
                results.ProcessingTimer.Start();
                await OutboxRepository.UpdateOutboxItemsAsync(processedItems, options.ItemUpdatingBatchSize).ConfigureAwait(false);

                results.ProcessingTimer.Stop();
            }

            options.LogDebugCallback?.Invoke(
                $"Finished updating the Outbox for [{processedItems.Count}] items in" +
                $" [{results.ProcessingTimer.Elapsed.ToElapsedTimeDescriptiveFormat()}]!"
                );
        }
        public virtual async Task <ISqlTransactionalOutboxProcessingResults <TUniqueIdentifier> > ProcessPendingOutboxItemsAsync(
            OutboxProcessingOptions processingOptions = null,
            bool throwExceptionOnFailure = false
            )
        {
            var options = processingOptions ?? OutboxProcessingOptions.DefaultOutboxProcessingOptions;
            var results = new OutboxProcessingResults <TUniqueIdentifier>();

            results.ProcessingTimer.Start();

            //Retrieve items to e processed from the Repository (ALL Pending items available for publishing attempt!)
            var pendingOutboxItems = await OutboxRepository.RetrieveOutboxItemsAsync(
                OutboxItemStatus.Pending,
                options.ItemProcessingBatchSize
                ).ConfigureAwait(false);

            results.ProcessingTimer.Stop();

            //Short Circuit if there is nothing to process!
            if (pendingOutboxItems.Count <= 0)
            {
                options.LogDebugCallback?.Invoke($"There are no outbox items to process; processing completed at [{DateTime.Now}].");
                return(results);
            }

            options.LogDebugCallback?.Invoke(
                $"Starting Outbox Processing of [{pendingOutboxItems.Count}] outbox items, retrieved in" +
                $" [{results.ProcessingTimer.Elapsed.ToElapsedTimeDescriptiveFormat()}], at [{DateTime.Now}]..."
                );

            //Attempt the acquire the Distributed Mutex Lock (if specified)!
            options.LogDebugCallback?.Invoke($"{nameof(options.FifoEnforcedPublishingEnabled)} = {options.FifoEnforcedPublishingEnabled}");

            results.ProcessingTimer.Start();

            await using var distributedMutex = options.FifoEnforcedPublishingEnabled
                ? await OutboxRepository.AcquireDistributedProcessingMutexAsync().ConfigureAwait(false)
                : new NoOpAsyncDisposable();

            //The distributed Mutex will ONLY be null if it could not be acquired; otherwise our
            //  NoOp will be successfully initialized if locking is disabled.
            if (distributedMutex == null)
            {
                const string mutexErrorMessage = "Distributed Mutex Lock could not be acquired; processing will not continue.";
                options.LogDebugCallback?.Invoke(mutexErrorMessage);

                if (throwExceptionOnFailure)
                {
                    throw new Exception(mutexErrorMessage);
                }

                return(results);
            }

            //Now EXECUTE & PROCESS the Items and Update the Outbox appropriately...
            //NOTE: It's CRITICAL that we attempt to Publish BEFORE we update the results in the TransactionalOutbox,
            //      this ensures that we guarantee at-least-once delivery because the item will be retried at a later point
            //      if anything fails with the update.
            await ProcessOutboxItemsInternalAsync(
                pendingOutboxItems,
                options,
                results,
                throwExceptionOnFailure
                ).ConfigureAwait(false);

            return(results);
        }