Browse Source

Added unit tests.

pull/112/head
Halil İbrahim Kalkan 9 years ago
parent
commit
275a64380b
  1. 14
      src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/EfCoreTransactionApi.cs
  2. 20
      src/Volo.Abp/Volo/Abp/Uow/ChildUnitOfWork.cs
  3. 12
      src/Volo.Abp/Volo/Abp/Uow/ISupportsRollback.cs
  4. 8
      src/Volo.Abp/Volo/Abp/Uow/IUnitOfWork.cs
  5. 73
      src/Volo.Abp/Volo/Abp/Uow/UnitOfWork.cs
  6. 20
      src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkEventArgs.cs
  7. 12
      src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkFailedEventArgs.cs
  8. 21
      test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Transaction_Tests.cs
  9. 31
      test/Volo.Abp.Tests/Volo/Abp/Uow/UnitOfWork_Events_Tests.cs

14
src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/EfCoreTransactionApi.cs

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

20
src/Volo.Abp/Volo/Abp/Uow/ChildUnitOfWork.cs

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

12
src/Volo.Abp/Volo/Abp/Uow/ISupportsRollback.cs

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

8
src/Volo.Abp/Volo/Abp/Uow/IUnitOfWork.cs

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

73
src/Volo.Abp/Volo/Abp/Uow/UnitOfWork.cs

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

20
src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkEventArgs.cs

@ -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;
}
}
}

12
src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkFailedEventArgs.cs

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

21
test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Transaction_Tests.cs

@ -4,6 +4,7 @@ using Microsoft.Extensions.DependencyInjection;
using Shouldly; using Shouldly;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
using Volo.Abp.TestApp.Domain; using Volo.Abp.TestApp.Domain;
using Volo.Abp.Uow;
using Xunit; using Xunit;
namespace Volo.Abp.EntityFrameworkCore namespace Volo.Abp.EntityFrameworkCore
@ -11,10 +12,12 @@ namespace Volo.Abp.EntityFrameworkCore
public class Transaction_Tests : EntityFrameworkCoreTestBase public class Transaction_Tests : EntityFrameworkCoreTestBase
{ {
private readonly IRepository<Person> _personRepository; private readonly IRepository<Person> _personRepository;
private readonly IUnitOfWorkManager _unitOfWorkManager;
public Transaction_Tests() public Transaction_Tests()
{ {
_personRepository = ServiceProvider.GetRequiredService<IRepository<Person>>(); _personRepository = ServiceProvider.GetRequiredService<IRepository<Person>>();
_unitOfWorkManager = ServiceProvider.GetRequiredService<IUnitOfWorkManager>();
} }
[Fact] [Fact]
@ -31,7 +34,7 @@ namespace Volo.Abp.EntityFrameworkCore
throw new Exception(exceptionMessage); 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); var person = await _personRepository.FindAsync(personId);
person.ShouldBeNull(); 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();
}
} }
} }

31
test/Volo.Abp.Tests/Volo/Abp/Uow/UnitOfWork_Events_Tests.cs

@ -108,5 +108,36 @@ namespace Volo.Abp.Uow
failed.ShouldBeTrue(); failed.ShouldBeTrue();
disposed.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