public async Task ReleaseLockAsync_should_throw_when_update_fails()
        {
            var state  = DummyState.New();
            var lockId = Guid.NewGuid();

            var updateResult = NSubstitute.Substitute.ForPartsOf <UpdateResult>();

            updateResult.MatchedCount.ReturnsForAnyArgs(0);

            var repo = NSubstitute.Substitute.For <IMongoCollection <Entities.SagaState> >();

            repo.UpdateOneAsync((FilterDefinition <Entities.SagaState>)null,
                                (UpdateDefinition <Entities.SagaState>)null,
                                (UpdateOptions)null,
                                CancellationToken.None)
            .ReturnsForAnyArgs(updateResult);

            var dbContext = NSubstitute.Substitute.For <IDbContext>();

            dbContext.SagaStates.Returns(repo);

            var serializer = NSubstitute.Substitute.For <ISerializer>();
            var sut        = new CosmosSagaStateRepository(dbContext, serializer, CosmosSagaStateRepositoryOptions.Default);

            await Assert.ThrowsAsync <LockException>(async() =>
                                                     await sut.ReleaseLockAsync <DummyState>(state, lockId));
        }
        public async Task ReleaseLockAsync_should_use_not_transaction_when_not_available()
        {
            var state  = DummyState.New();
            var lockId = Guid.NewGuid();

            var updateResult = NSubstitute.Substitute.ForPartsOf <UpdateResult>();

            updateResult.MatchedCount.ReturnsForAnyArgs(1);

            var repo = NSubstitute.Substitute.For <IMongoCollection <Entities.SagaState> >();

            repo.UpdateOneAsync((FilterDefinition <Entities.SagaState>)null,
                                (UpdateDefinition <Entities.SagaState>)null,
                                (UpdateOptions)null,
                                CancellationToken.None)
            .ReturnsForAnyArgs(updateResult);

            var dbContext = NSubstitute.Substitute.For <IDbContext>();

            dbContext.SagaStates.Returns(repo);
            dbContext.Transaction.ReturnsNull();

            var serializer = NSubstitute.Substitute.For <ISerializer>();
            var sut        = new CosmosSagaStateRepository(dbContext, serializer, CosmosSagaStateRepositoryOptions.Default);

            await sut.ReleaseLockAsync <DummyState>(state, lockId);

            await repo.Received(1)
            .UpdateOneAsync(Arg.Any <FilterDefinition <Entities.SagaState> >(),
                            Arg.Any <UpdateDefinition <Entities.SagaState> >(),
                            Arg.Any <UpdateOptions>(),
                            Arg.Any <CancellationToken>());
        }
Exemple #3
0
        public async Task LockAsync_should_throw_if_item_locked()
        {
            var sut = CreateSut();

            var newState = DummyState.New();

            await sut.LockAsync(newState.Id, newState, CancellationToken.None);

            var ex = await Assert.ThrowsAsync <LockException>(async() => await sut.LockAsync(newState.Id, newState, CancellationToken.None));

            ex.Message.Should().Contain($"saga state '{newState.Id}' is already locked");
        }
Exemple #4
0
        public async Task LockAsync_should_create_and_return_locked_item_if_not_existing()
        {
            var sut = CreateSut();

            var newState = DummyState.New();

            var(state, lockId) = await sut.LockAsync(newState.Id, newState, CancellationToken.None);

            state.Should().NotBeNull();
            state.Id.Should().Be(newState.Id);
            state.Bar.Should().Be(newState.Bar);
            state.Foo.Should().Be(newState.Foo);
        }
        public async Task LockAsync_should_lock_item()
        {
            var sut = CreateSut();

            var newState = DummyState.New();

            var(_, lockId) = await sut.LockAsync(newState.Id, newState, CancellationToken.None);

            var lockedState = await _fixture.DbContext.SagaStates.FirstOrDefaultAsync(e =>
                                                                                      e.LockId == lockId && e.CorrelationId == newState.Id);

            lockedState.Should().NotBeNull();
        }
Exemple #6
0
        public async Task LockAsync_should_throw_if_item_locked()
        {
            var serializer = new JsonSerializer();

            var options = new MongoSagaStateRepositoryOptions(TimeSpan.FromMinutes(1));
            var sut     = new MongoSagaStateRepository(_fixture.DbContext, serializer, options);

            var newState = DummyState.New();

            var(state, lockId) = await sut.LockAsync(newState.Id, newState, CancellationToken.None);

            var ex = await Assert.ThrowsAsync <LockException>(async() => await sut.LockAsync(newState.Id, newState, CancellationToken.None));

            ex.Message.Should().Contain($"saga state '{state.Id}' is already locked");
        }
Exemple #7
0
        public async Task LockAsync_should_return_state_if_lock_expired()
        {
            var options = new CosmosSagaStateRepositoryOptions(TimeSpan.Zero);
            var sut     = CreateSut(options);

            var newState = DummyState.New();

            var(firstState, firstLockId) = await sut.LockAsync(newState.Id, newState, CancellationToken.None);

            await Task.Delay(500);

            var(secondState, secondLockId) = await sut.LockAsync(newState.Id, newState, CancellationToken.None);

            secondLockId.Should().NotBe(firstLockId);
            secondState.Should().NotBeNull();
        }
Exemple #8
0
        public async Task LockAsync_should_lock_item()
        {
            var sut = CreateSut();

            var newState = DummyState.New();

            var(state, lockId) = await sut.LockAsync(newState.Id, newState, CancellationToken.None);

            var filter = Builders <Entities.SagaState> .Filter.Eq(e => e.LockId, lockId);

            var cursor = await _fixture.DbContext.SagaStates.FindAsync(filter);

            var lockedState = await cursor.FirstOrDefaultAsync();

            lockedState.Should().NotBeNull();
        }
Exemple #9
0
        public async Task LockAsync_should_create_and_return_locked_item_if_not_existing()
        {
            var serializer = new JsonSerializer();

            var options = new MongoSagaStateRepositoryOptions(TimeSpan.FromMinutes(1));
            var sut     = new MongoSagaStateRepository(_fixture.DbContext, serializer, options);

            var newState = DummyState.New();

            var(state, lockId) = await sut.LockAsync(newState.Id, newState, CancellationToken.None);

            state.Should().NotBeNull();
            state.Id.Should().Be(newState.Id);
            state.Bar.Should().Be(newState.Bar);
            state.Foo.Should().Be(newState.Foo);
        }
Exemple #10
0
        public async Task LockAsync_should_allow_different_saga_state_types_to_share_the_correlation_id()
        {
            var serializer = new JsonSerializer();

            var options = new MongoSagaStateRepositoryOptions(TimeSpan.FromMinutes(1));
            var sut     = new MongoSagaStateRepository(_fixture.DbContext, serializer, options);

            var newState = DummyState.New();

            var(state, lockId) = await sut.LockAsync(newState.Id, newState, CancellationToken.None);

            var newState2 = new DummyState2(state.Id);

            newState2.Id.Should().Be(newState.Id);

            var(state2, lockId2) = await sut.LockAsync(newState2.Id, newState2, CancellationToken.None);

            state2.Should().NotBeNull();
            state2.Id.Should().Be(newState.Id);
        }
        public async Task ReleaseLockAsync_should_throw_when_release_lock_fails()
        {
            var newState = DummyState.New();

            var coll = NSubstitute.Substitute.For <IMongoCollection <Entities.SagaState> >();

            coll.UpdateOneAsync(Arg.Any <FilterDefinition <Entities.SagaState> >(),
                                Arg.Any <UpdateDefinition <Entities.SagaState> >(),
                                Arg.Any <UpdateOptions>(),
                                Arg.Any <CancellationToken>())
            .ReturnsForAnyArgs((UpdateResult)null);

            var dbContext = NSubstitute.Substitute.For <IDbContext>();

            dbContext.SagaStates.Returns(coll);

            var serializer = NSubstitute.Substitute.For <ISerializer>();
            var options    = new CosmosSagaStateRepositoryOptions(TimeSpan.FromMinutes(1));
            var sut        = new CosmosSagaStateRepository(dbContext, serializer, options);

            var ex = await Assert.ThrowsAsync <LockException>(async() => await sut.ReleaseLockAsync(newState, Guid.NewGuid(), CancellationToken.None));

            ex.Message.Should().Contain("unable to release lock on saga state");
        }