using e_suite.Database.Core.UnitTests.Helpers; using e_suite.Database.Core.UnitTests.Helpers.Tables; using eSuite.Core.Clock; using Moq; using NUnit.Framework; namespace e_suite.Database.Core.UnitTests; [TestFixture] public class SunDatabaseEntityContextUnitTests { protected TestDbContextFactory testDbContextFactory = null!; protected Mock _clockMock = null!; public DateTimeOffset TestNow = DateTimeOffset.Now; protected TestDbContext TestDbContext = null!; [SetUp] public void Setup() { testDbContextFactory = new TestDbContextFactory(); _clockMock = new Mock(); _clockMock.Setup(x => x.GetNow).Returns(() => TestNow); TestDbContext = testDbContextFactory.CreateContext(_clockMock.Object); } [Test] public void OnModelCreating_Executes_WithoutExceptions() { //Arrange //Act // dealt with by the Setup method, as this ensures the database is created. //Assert Assert.That(TestDbContext.TableWithKey.Count(), Is.EqualTo(1)); } [Test] public async Task TransActionAsyncAction_Executing_CodeRunsInATransaction() { //Arrange Guid? transactionId = null; //Act await TestDbContext.TransactionAsync(async () => { transactionId = TestDbContext.Database.CurrentTransaction?.TransactionId; await TestDbContext.SaveChangesAsync(); }); //Assert Assert.That(transactionId, Is.Not.Null); //Was in a transaction when the code was executed Assert.That(TestDbContext.Database.CurrentTransaction?.TransactionId, Is.Null); //No longer in a transaction } [Test] public async Task TransActionAsyncAction_AlreadyInTransaction_DoesNotStartAnotherTransaction() { //Arrange Guid? transactionId = null; Guid? innerTransactionId = null; await TestDbContext.TransactionAsync(async () => { transactionId = TestDbContext.Database.CurrentTransaction?.TransactionId; //Act await TestDbContext.TransactionAsync( async () => { innerTransactionId = TestDbContext.Database.CurrentTransaction?.TransactionId; await TestDbContext.SaveChangesAsync(); }); }); //Assert Assert.That(transactionId, Is.Not.Null); //Was in a transaction when the code was executed Assert.That(innerTransactionId, Is.EqualTo(transactionId)); //The inner transaction is the same as the outer transaction. Transaction inception is not allowed. } [Test] public async Task TransActionAsyncAction_InsertedRecordWithNoException_TransactionCompletes() { //Arrange var newItem = new TableWithKey() { Id = 2, TotalTimeMS = 5000 }; Assert.That(TestDbContext.TableWithKey.Count(), Is.EqualTo(1)); //Act await TestDbContext.TransactionAsync(async () => { TestDbContext.TableWithKey.Add(newItem); await TestDbContext.SaveChangesAsync(); }); //Assert Assert.That(TestDbContext.TableWithKey.Count(), Is.EqualTo(2)); } [Test] public async Task TransActionAsyncAction_InsertedRecordThenException_TransactionIsRolledback() { //Arrange var newItem = new TableWithKey() { Id = 2, TotalTimeMS = 5000 }; Assert.That(TestDbContext.TableWithKey.Count(), Is.EqualTo(1)); //Act try { await TestDbContext.TransactionAsync(async () => { TestDbContext.TableWithKey.Add(newItem); await TestDbContext.SaveChangesAsync(); throw new Exception("Testing rollback"); }); } catch { //This was supposed to happen } //Assert Assert.That(TestDbContext.TableWithKey.Count(), Is.EqualTo(1)); } [Test] public async Task TransActionAsyncFunc_Executing_CodeRunsInATransaction() { //Arrange Guid? transactionId = null; //Act var result = await TestDbContext.TransactionAsync(async () => { transactionId = TestDbContext.Database.CurrentTransaction?.TransactionId; await TestDbContext.SaveChangesAsync(); return true; }); //Assert Assert.That(result, Is.True); Assert.That(transactionId, Is.Not.Null); //Was in a transaction when the code was executed Assert.That(TestDbContext.Database.CurrentTransaction?.TransactionId, Is.Null); //No longer in a transaction } [Test] public async Task TransActionAsyncFunc_InsertedRecordThenException_TransactionIsRolledback() { //Arrange var newItem = new TableWithKey() { Id = 2, TotalTimeMS = 5000 }; Assert.That(TestDbContext.TableWithKey.Count(), Is.EqualTo(1)); //Act try { var result = await TestDbContext.TransactionAsync(async () => { TestDbContext.TableWithKey.Add(newItem); await TestDbContext.SaveChangesAsync(); throw new Exception("Testing rollback"); #pragma warning disable CS0162 //This code will never be hit because this is a test, but it's needed so that the code will compile. return 1; #pragma warning restore CS0162 }); } catch { //This was supposed to happen } //Assert Assert.That(TestDbContext.TableWithKey.Count(), Is.EqualTo(1)); } }