Added unit tests.

pull/112/head
Halil İbrahim Kalkan 7 years ago
parent 1a6778b4c6
commit 275a64380b

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
@ -6,7 +7,7 @@ using Volo.Abp.EntityFrameworkCore;
namespace Volo.Abp.Uow.EntityFrameworkCore
{
public class EfCoreTransactionApi : ITransactionApi
public class EfCoreTransactionApi : ITransactionApi, ISupportsRollback
{
public IDbContextTransaction DbContextTransaction { get; }
public DbContext StarterDbContext { get; }
@ -44,5 +45,16 @@ namespace Volo.Abp.Uow.EntityFrameworkCore
{
DbContextTransaction.Dispose();
}
public void Rollback()
{
DbContextTransaction.Rollback();
}
public Task RollbackAsync(CancellationToken cancellationToken)
{
DbContextTransaction.Rollback();
return Task.CompletedTask;
}
}
}

@ -17,9 +17,9 @@ namespace Volo.Abp.Uow
public string ReservationName => _parent.ReservationName;
public event EventHandler Completed;
public event EventHandler<UnitOfWorkEventArgs> Completed;
public event EventHandler<UnitOfWorkFailedEventArgs> Failed;
public event EventHandler Disposed;
public event EventHandler<UnitOfWorkEventArgs> Disposed;
public IServiceProvider ServiceProvider => _parent.ServiceProvider;
@ -60,17 +60,27 @@ namespace Volo.Abp.Uow
{
return _parent.SaveChangesAsync(cancellationToken);
}
public void Complete()
{
}
public Task CompleteAsync(CancellationToken cancellationToken = default(CancellationToken))
{
return Task.CompletedTask;
}
public void Rollback()
{
_parent.Rollback();
}
public Task RollbackAsync(CancellationToken cancellationToken = default(CancellationToken))
{
return _parent.RollbackAsync(cancellationToken);
}
public IDatabaseApi FindDatabaseApi(string key)
{
return _parent.FindDatabaseApi(key);

@ -0,0 +1,12 @@
using System.Threading;
using System.Threading.Tasks;
namespace Volo.Abp.Uow
{
public interface ISupportsRollback
{
void Rollback();
Task RollbackAsync(CancellationToken cancellationToken);
}
}

@ -9,11 +9,11 @@ namespace Volo.Abp.Uow
{
Guid Id { get; }
event EventHandler Completed;
event EventHandler<UnitOfWorkEventArgs> Completed;
event EventHandler<UnitOfWorkFailedEventArgs> Failed;
event EventHandler Disposed;
event EventHandler<UnitOfWorkEventArgs> Disposed;
IUnitOfWorkOptions Options { get; }
@ -36,5 +36,9 @@ namespace Volo.Abp.Uow
void Complete();
Task CompleteAsync(CancellationToken cancellationToken = default(CancellationToken));
void Rollback();
Task RollbackAsync(CancellationToken cancellationToken = default(CancellationToken));
}
}

@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
@ -20,9 +19,9 @@ namespace Volo.Abp.Uow
public string ReservationName { get; set; }
public event EventHandler Completed;
public event EventHandler<UnitOfWorkEventArgs> Completed;
public event EventHandler<UnitOfWorkFailedEventArgs> Failed;
public event EventHandler Disposed;
public event EventHandler<UnitOfWorkEventArgs> Disposed;
public IServiceProvider ServiceProvider { get; }
@ -33,6 +32,7 @@ namespace Volo.Abp.Uow
private Exception _exception;
private bool _isCompleted;
private bool _isDisposed;
private bool _isRolledback;
public UnitOfWork(IServiceProvider serviceProvider, IOptions<UnitOfWorkDefaultOptions> options)
{
@ -90,7 +90,13 @@ namespace Volo.Abp.Uow
public void Complete()
{
if (_isRolledback)
{
return;
}
PreventMultipleComplete();
try
{
SaveChanges();
@ -106,6 +112,11 @@ namespace Volo.Abp.Uow
public async Task CompleteAsync(CancellationToken cancellationToken = default(CancellationToken))
{
if (_isRolledback)
{
return;
}
PreventMultipleComplete();
try
@ -121,6 +132,52 @@ namespace Volo.Abp.Uow
}
}
public void Rollback()
{
if (_isRolledback)
{
return;
}
_isRolledback = true;
foreach (var databaseApi in _databaseApis.Values)
{
(databaseApi as ISupportsRollback)?.Rollback();
}
foreach (var transactionApi in _transactionApis.Values)
{
(transactionApi as ISupportsRollback)?.Rollback();
}
}
public async Task RollbackAsync(CancellationToken cancellationToken = default(CancellationToken))
{
if (_isRolledback)
{
return;
}
_isRolledback = true;
foreach (var databaseApi in _databaseApis.Values)
{
if (databaseApi is ISupportsRollback)
{
await (databaseApi as ISupportsRollback).RollbackAsync(cancellationToken);
}
}
foreach (var transactionApi in _transactionApis.Values)
{
if (transactionApi is ISupportsRollback)
{
await (transactionApi as ISupportsRollback).RollbackAsync(cancellationToken);
}
}
}
public IDatabaseApi FindDatabaseApi(string key)
{
return _databaseApis.GetOrDefault(key);
@ -177,17 +234,17 @@ namespace Volo.Abp.Uow
protected virtual void OnCompleted()
{
Completed.InvokeSafely(this);
Completed.InvokeSafely(this, new UnitOfWorkEventArgs(this));
}
protected virtual void OnFailed(Exception exception)
protected virtual void OnFailed()
{
Failed.InvokeSafely(this, new UnitOfWorkFailedEventArgs(exception));
Failed.InvokeSafely(this, new UnitOfWorkFailedEventArgs(this, _exception, _isRolledback));
}
protected virtual void OnDisposed()
{
Disposed.InvokeSafely(this);
Disposed.InvokeSafely(this, new UnitOfWorkEventArgs(this));
}
public void Dispose()
@ -201,7 +258,7 @@ namespace Volo.Abp.Uow
if (!_isCompleted || _exception != null)
{
OnFailed(_exception);
OnFailed();
}
OnDisposed();

@ -0,0 +1,20 @@
using System;
using JetBrains.Annotations;
namespace Volo.Abp.Uow
{
public class UnitOfWorkEventArgs : EventArgs
{
/// <summary>
/// Reference to the unit of work related to this event.
/// </summary>
public IUnitOfWork UnitOfWork { get; }
public UnitOfWorkEventArgs([NotNull] IUnitOfWork unitOfWork)
{
Check.NotNull(unitOfWork, nameof(unitOfWork));
UnitOfWork = unitOfWork;
}
}
}

@ -6,7 +6,7 @@ namespace Volo.Abp.Uow
/// <summary>
/// Used as event arguments on <see cref="IUnitOfWork.Failed"/> event.
/// </summary>
public class UnitOfWorkFailedEventArgs : EventArgs
public class UnitOfWorkFailedEventArgs : UnitOfWorkEventArgs
{
/// <summary>
/// Exception that caused failure. This is set only if an error occured during <see cref="IUnitOfWork.Complete"/>.
@ -16,13 +16,19 @@ namespace Volo.Abp.Uow
[CanBeNull]
public Exception Exception { get; }
/// <summary>
/// True, if the unit of work is manually rolled back.
/// </summary>
public bool IsRolledback { get; }
/// <summary>
/// Creates a new <see cref="UnitOfWorkFailedEventArgs"/> object.
/// </summary>
/// <param name="exception">Exception that caused failure</param>
public UnitOfWorkFailedEventArgs([CanBeNull] Exception exception)
public UnitOfWorkFailedEventArgs([NotNull] IUnitOfWork unitOfWork, [CanBeNull] Exception exception, bool isRolledback)
: base(unitOfWork)
{
Exception = exception;
IsRolledback = isRolledback;
}
}
}

@ -4,6 +4,7 @@ using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.TestApp.Domain;
using Volo.Abp.Uow;
using Xunit;
namespace Volo.Abp.EntityFrameworkCore
@ -11,10 +12,12 @@ namespace Volo.Abp.EntityFrameworkCore
public class Transaction_Tests : EntityFrameworkCoreTestBase
{
private readonly IRepository<Person> _personRepository;
private readonly IUnitOfWorkManager _unitOfWorkManager;
public Transaction_Tests()
{
_personRepository = ServiceProvider.GetRequiredService<IRepository<Person>>();
_unitOfWorkManager = ServiceProvider.GetRequiredService<IUnitOfWorkManager>();
}
[Fact]
@ -31,7 +34,7 @@ namespace Volo.Abp.EntityFrameworkCore
throw new Exception(exceptionMessage);
});
}
catch (Exception e) when(e.Message == exceptionMessage)
catch (Exception e) when (e.Message == exceptionMessage)
{
}
@ -39,5 +42,21 @@ namespace Volo.Abp.EntityFrameworkCore
var person = await _personRepository.FindAsync(personId);
person.ShouldBeNull();
}
[Fact]
public async Task Should_Rollback_Transaction_Manually()
{
var personId = Guid.NewGuid();
await WithUnitOfWorkAsync(async () =>
{
_unitOfWorkManager.Current.ShouldNotBeNull();
await _personRepository.InsertAsync(new Person(personId, "Adam", 42));
await _unitOfWorkManager.Current.RollbackAsync();
});
var person = await _personRepository.FindAsync(personId);
person.ShouldBeNull();
}
}
}

@ -108,5 +108,36 @@ namespace Volo.Abp.Uow
failed.ShouldBeTrue();
disposed.ShouldBeTrue();
}
[InlineData(true)]
[InlineData(false)]
[Theory]
public void Should_Trigger_Failed_If_Rolled_Back(bool callComplete)
{
var completed = false;
var failed = false;
var disposed = false;
Assert.Throws<Exception>(() =>
{
using (var uow = _unitOfWorkManager.Begin())
{
uow.Completed += (sender, args) => completed = true;
uow.Failed += (sender, args) => { failed = true; args.IsRolledback.ShouldBeTrue(); };
uow.Disposed += (sender, args) => disposed = true;
uow.Rollback();
if (callComplete)
{
uow.Complete();
}
}
}).Message.ShouldBe("test exception");
completed.ShouldBeFalse();
failed.ShouldBeTrue();
disposed.ShouldBeTrue();
}
}
}

Loading…
Cancel
Save