From d5fb31b3a2ebe9eab3a64aad2258bbdf09c55a93 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 9 Mar 2021 11:32:23 +0100 Subject: [PATCH] Reintroduce tests --- .../Persistence/LocksTests.cs | 142 ++++++++++++++++++ 1 file changed, 142 insertions(+) diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/LocksTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/LocksTests.cs index 3b1cbc06ca..b68bb267cd 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/LocksTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/LocksTests.cs @@ -4,6 +4,7 @@ using System.Data.SqlClient; using System.Linq; using System.Text; using System.Threading; +using System.Threading.Tasks; using NPoco; using NUnit.Framework; using Umbraco.Cms.Core; @@ -321,6 +322,147 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence Assert.IsNull(e2); } + [Test] + public void Throws_When_Lock_Timeout_Is_Exceeded() + { + using (ExecutionContext.SuppressFlow()) + { + + + var t1 = Task.Run(() => + { + using (var scope = ScopeProvider.CreateScope()) + { + + Console.WriteLine("Write lock A"); + // This will acquire right away + scope.WriteLock(TimeSpan.FromMilliseconds(2000), Constants.Locks.ContentTree); + Thread.Sleep(6000); // Wait longer than the Read Lock B timeout + scope.Complete(); + Console.WriteLine("Finished Write lock A"); + } + }); + + Thread.Sleep(500); // 100% sure task 1 starts first + + var t2 = Task.Run(() => + { + using (var scope = ScopeProvider.CreateScope()) + { + Console.WriteLine("Read lock B"); + + // This will wait for the write lock to release but it isn't going to wait long + // enough so an exception will be thrown. + Assert.Throws(() => + scope.ReadLock(TimeSpan.FromMilliseconds(3000), Constants.Locks.ContentTree)); + scope.Complete(); + Console.WriteLine("Finished Read lock B"); + } + }); + + var t3 = Task.Run(() => + { + using (var scope = ScopeProvider.CreateScope()) + { + Console.WriteLine("Write lock C"); + + // This will wait for the write lock to release but it isn't going to wait long + // enough so an exception will be thrown. + Assert.Throws(() => + scope.WriteLock(TimeSpan.FromMilliseconds(3000), Constants.Locks.ContentTree)); + + scope.Complete(); + Console.WriteLine("Finished Write lock C"); + } + }); + + Task.WaitAll(t1, t2, t3); + } + } + + [Test] + public void Read_Lock_Waits_For_Write_Lock() + { + var locksCompleted = 0; + + using (ExecutionContext.SuppressFlow()) + { + var t1 = Task.Run(() => + { + using (var scope = ScopeProvider.CreateScope()) + { + Console.WriteLine("Write lock A"); + // This will acquire right away + scope.WriteLock(TimeSpan.FromMilliseconds(2000), Constants.Locks.ContentTree); + Thread.Sleep(4000); // Wait less than the Read Lock B timeout + scope.Complete(); + Interlocked.Increment(ref locksCompleted); + Console.WriteLine("Finished Write lock A"); + } + }); + + Thread.Sleep(500); // 100% sure task 1 starts first + + var t2 = Task.Run(() => + { + using (var scope = ScopeProvider.CreateScope()) + { + Console.WriteLine("Read lock B"); + + // This will wait for the write lock to release + Assert.DoesNotThrow(() => + scope.ReadLock(TimeSpan.FromMilliseconds(6000), Constants.Locks.ContentTree)); + + Assert.GreaterOrEqual(locksCompleted, 1); + + scope.Complete(); + Interlocked.Increment(ref locksCompleted); + Console.WriteLine("Finished Read lock B"); + } + }); + + + var t3 = Task.Run(() => + { + using (var scope = ScopeProvider.CreateScope()) + { + Console.WriteLine("Read lock C"); + + // This will wait for the write lock to release + Assert.DoesNotThrow(() => + scope.ReadLock(TimeSpan.FromMilliseconds(6000), Constants.Locks.ContentTree)); + + Assert.GreaterOrEqual(locksCompleted, 1); + + scope.Complete(); + Interlocked.Increment(ref locksCompleted); + Console.WriteLine("Finished Read lock C"); + } + }); + + Task.WaitAll(t1, t2, t3); + } + + Assert.AreEqual(3, locksCompleted); + } + + [Test] + public void Lock_Exceeds_Command_Timeout() + { + using (var scope = ScopeProvider.CreateScope()) + { + var realDb = (Database)scope.Database; + realDb.CommandTimeout = 1000; + + Console.WriteLine("Write lock A"); + // TODO: In theory this would throw + scope.WriteLock(TimeSpan.FromMilliseconds(3000), Constants.Locks.ContentTree); + scope.Complete(); + Console.WriteLine("Finished Write lock A"); + } + } + + private void NoDeadLockTestThread(int id, EventWaitHandle myEv, WaitHandle otherEv, ref Exception exception) { using (var scope = ScopeProvider.CreateScope())