2021-03-02 10:53:10 +01:00
using System ;
2021-03-15 08:54:52 +01:00
using System.Collections.Generic ;
2021-07-06 15:09:56 -06:00
using System.Linq ;
2021-03-19 16:17:39 +01:00
using CSharpTest.Net.Interfaces ;
using Microsoft.Extensions.Logging ;
using Microsoft.Extensions.Logging.Abstractions ;
using Microsoft.Extensions.Options ;
2021-03-02 10:53:10 +01:00
using Moq ;
using NPoco ;
using NUnit.Framework ;
2021-03-19 16:17:39 +01:00
using Umbraco.Cms.Core ;
using Umbraco.Cms.Core.Cache ;
using Umbraco.Cms.Core.Configuration.Models ;
using Umbraco.Cms.Core.Events ;
using Umbraco.Cms.Core.Hosting ;
using Umbraco.Cms.Core.IO ;
using Umbraco.Cms.Core.Scoping ;
2021-04-27 09:52:17 +02:00
using Umbraco.Cms.Core.Strings ;
2021-03-19 16:17:39 +01:00
using Umbraco.Cms.Infrastructure.Persistence ;
using Umbraco.Cms.Infrastructure.Persistence.SqlSyntax ;
2021-03-02 10:53:10 +01:00
2021-03-19 16:17:39 +01:00
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Scoping
2021-03-02 10:53:10 +01:00
{
[TestFixture]
public class ScopeUnitTests
{
/// <summary>
/// Creates a ScopeProvider with mocked internals.
/// </summary>
/// <param name="syntaxProviderMock">The mock of the ISqlSyntaxProvider2, used to count method calls.</param>
/// <returns></returns>
2021-03-19 16:17:39 +01:00
private ScopeProvider GetScopeProvider ( out Mock < ISqlSyntaxProvider > syntaxProviderMock )
2021-03-02 10:53:10 +01:00
{
2021-03-19 16:17:39 +01:00
var loggerFactory = NullLoggerFactory . Instance ;
2021-04-27 09:52:17 +02:00
var fileSystems = new FileSystems ( loggerFactory ,
Mock . Of < IIOHelper > ( ) , Mock . Of < IOptions < GlobalSettings > > ( ) , Mock . Of < IHostingEnvironment > ( ) ) ;
2021-07-06 15:09:56 -06:00
var mediaFileManager = new MediaFileManager (
Mock . Of < IFileSystem > ( ) ,
Mock . Of < IMediaPathScheme > ( ) ,
loggerFactory . CreateLogger < MediaFileManager > ( ) ,
Mock . Of < IShortStringHelper > ( ) ,
Mock . Of < IServiceProvider > ( ) ,
Options . Create ( new ContentSettings ( ) ) ) ;
2021-03-02 10:53:10 +01:00
var databaseFactory = new Mock < IUmbracoDatabaseFactory > ( ) ;
var database = new Mock < IUmbracoDatabase > ( ) ;
var sqlContext = new Mock < ISqlContext > ( ) ;
2021-03-19 16:17:39 +01:00
syntaxProviderMock = new Mock < ISqlSyntaxProvider > ( ) ;
2021-03-02 10:53:10 +01:00
// Setup mock of database factory to return mock of database.
databaseFactory . Setup ( x = > x . CreateDatabase ( ) ) . Returns ( database . Object ) ;
2021-09-13 21:09:47 +10:00
databaseFactory . Setup ( x = > x . SqlContext ) . Returns ( sqlContext . Object ) ;
2021-03-02 10:53:10 +01:00
// Setup mock of database to return mock of sql SqlContext
database . Setup ( x = > x . SqlContext ) . Returns ( sqlContext . Object ) ;
// Setup mock of ISqlContext to return syntaxProviderMock
sqlContext . Setup ( x = > x . SqlSyntax ) . Returns ( syntaxProviderMock . Object ) ;
2021-03-19 16:17:39 +01:00
return new ScopeProvider (
databaseFactory . Object ,
2021-04-27 09:52:17 +02:00
fileSystems ,
2021-03-19 16:17:39 +01:00
Options . Create ( new CoreDebugSettings ( ) ) ,
2021-04-27 09:52:17 +02:00
mediaFileManager ,
2021-03-19 16:17:39 +01:00
loggerFactory . CreateLogger < ScopeProvider > ( ) ,
loggerFactory ,
Mock . Of < IRequestCache > ( ) ,
Mock . Of < IEventAggregator > ( ) ) ;
2021-03-02 10:53:10 +01:00
}
2021-09-13 21:09:47 +10:00
[Test]
public void Unused_Lazy_Locks_Cleared_At_Child_Scope ( )
{
var scopeProvider = GetScopeProvider ( out var syntaxProviderMock ) ;
2021-09-14 11:32:43 +02:00
var outerScope = scopeProvider . CreateScope ( ) ;
2021-09-13 21:09:47 +10:00
outerScope . ReadLock ( Constants . Locks . Domains ) ;
outerScope . ReadLock ( Constants . Locks . Languages ) ;
using ( var innerScope1 = ( Scope ) scopeProvider . CreateScope ( ) )
{
innerScope1 . ReadLock ( Constants . Locks . Domains ) ;
innerScope1 . ReadLock ( Constants . Locks . Languages ) ;
innerScope1 . Complete ( ) ;
}
using ( var innerScope2 = ( Scope ) scopeProvider . CreateScope ( ) )
{
innerScope2 . ReadLock ( Constants . Locks . Domains ) ;
innerScope2 . ReadLock ( Constants . Locks . Languages ) ;
// force resolving the locks
var locks = innerScope2 . GetReadLocks ( ) ;
innerScope2 . Complete ( ) ;
}
outerScope . Complete ( ) ;
Assert . DoesNotThrow ( ( ) = > outerScope . Dispose ( ) ) ;
2021-03-02 10:53:10 +01:00
}
[Test]
public void WriteLock_Acquired_Only_Once_Per_Key ( )
{
var scopeProvider = GetScopeProvider ( out var syntaxProviderMock ) ;
2021-09-13 21:09:47 +10:00
using ( var outerScope = ( Scope ) scopeProvider . CreateScope ( ) )
2021-03-02 10:53:10 +01:00
{
2021-09-13 21:09:47 +10:00
outerScope . EagerWriteLock ( Constants . Locks . Domains ) ;
outerScope . EagerWriteLock ( Constants . Locks . Languages ) ;
2021-03-02 10:53:10 +01:00
2021-09-13 21:09:47 +10:00
using ( var innerScope1 = ( Scope ) scopeProvider . CreateScope ( ) )
2021-03-02 10:53:10 +01:00
{
2021-09-13 21:09:47 +10:00
innerScope1 . EagerWriteLock ( Constants . Locks . Domains ) ;
innerScope1 . EagerWriteLock ( Constants . Locks . Languages ) ;
2021-03-02 10:53:10 +01:00
2021-09-13 21:09:47 +10:00
using ( var innerScope2 = ( Scope ) scopeProvider . CreateScope ( ) )
2021-03-02 10:53:10 +01:00
{
2021-09-13 21:09:47 +10:00
innerScope2 . EagerWriteLock ( Constants . Locks . Domains ) ;
innerScope2 . EagerWriteLock ( Constants . Locks . Languages ) ;
2021-03-02 10:53:10 +01:00
innerScope2 . Complete ( ) ;
}
innerScope1 . Complete ( ) ;
}
outerScope . Complete ( ) ;
}
syntaxProviderMock . Verify ( x = > x . WriteLock ( It . IsAny < IDatabase > ( ) , Constants . Locks . Domains ) , Times . Once ) ;
syntaxProviderMock . Verify ( x = > x . WriteLock ( It . IsAny < IDatabase > ( ) , Constants . Locks . Languages ) , Times . Once ) ;
}
2021-03-12 13:30:25 +01:00
[Test]
public void WriteLock_Acquired_Only_Once_When_InnerScope_Disposed ( )
{
var scopeProvider = GetScopeProvider ( out var syntaxProviderMock ) ;
2021-09-13 21:09:47 +10:00
using ( var outerScope = ( Scope ) scopeProvider . CreateScope ( ) )
2021-03-12 13:30:25 +01:00
{
2021-09-13 21:09:47 +10:00
outerScope . EagerWriteLock ( Constants . Locks . Languages ) ;
2021-03-12 13:30:25 +01:00
2021-09-13 21:09:47 +10:00
using ( var innerScope = ( Scope ) scopeProvider . CreateScope ( ) )
2021-03-12 13:30:25 +01:00
{
2021-09-13 21:09:47 +10:00
innerScope . EagerWriteLock ( Constants . Locks . Languages ) ;
innerScope . EagerWriteLock ( Constants . Locks . ContentTree ) ;
2021-03-12 13:30:25 +01:00
innerScope . Complete ( ) ;
}
2021-09-13 21:09:47 +10:00
outerScope . EagerWriteLock ( Constants . Locks . ContentTree ) ;
2021-03-12 13:30:25 +01:00
outerScope . Complete ( ) ;
}
syntaxProviderMock . Verify ( x = > x . WriteLock ( It . IsAny < IDatabase > ( ) , Constants . Locks . Languages ) , Times . Once ) ;
syntaxProviderMock . Verify ( x = > x . WriteLock ( It . IsAny < IDatabase > ( ) , Constants . Locks . ContentTree ) , Times . Once ) ;
}
2021-03-02 10:53:10 +01:00
[Test]
2021-09-13 21:09:47 +10:00
public void WriteLock_With_Timeout_Acquired_Only_Once_Per_Key ( )
{
2021-03-02 10:53:10 +01:00
var scopeProvider = GetScopeProvider ( out var syntaxProviderMock ) ;
var timeout = TimeSpan . FromMilliseconds ( 10000 ) ;
2021-09-13 21:09:47 +10:00
using ( var outerScope = ( Scope ) scopeProvider . CreateScope ( ) )
2021-03-02 10:53:10 +01:00
{
2021-09-13 21:09:47 +10:00
outerScope . EagerWriteLock ( timeout , Constants . Locks . Domains ) ;
outerScope . EagerWriteLock ( timeout , Constants . Locks . Languages ) ;
2021-03-02 10:53:10 +01:00
2021-09-13 21:09:47 +10:00
using ( var innerScope1 = ( Scope ) scopeProvider . CreateScope ( ) )
2021-03-02 10:53:10 +01:00
{
2021-09-13 21:09:47 +10:00
innerScope1 . EagerWriteLock ( timeout , Constants . Locks . Domains ) ;
innerScope1 . EagerWriteLock ( timeout , Constants . Locks . Languages ) ;
2021-03-02 10:53:10 +01:00
2021-09-13 21:09:47 +10:00
using ( var innerScope2 = ( Scope ) scopeProvider . CreateScope ( ) )
2021-03-02 10:53:10 +01:00
{
2021-09-13 21:09:47 +10:00
innerScope2 . EagerWriteLock ( timeout , Constants . Locks . Domains ) ;
innerScope2 . EagerWriteLock ( timeout , Constants . Locks . Languages ) ;
2021-03-02 10:53:10 +01:00
innerScope2 . Complete ( ) ;
}
innerScope1 . Complete ( ) ;
}
outerScope . Complete ( ) ;
}
syntaxProviderMock . Verify ( x = > x . WriteLock ( It . IsAny < IDatabase > ( ) , timeout , Constants . Locks . Domains ) , Times . Once ) ;
syntaxProviderMock . Verify ( x = > x . WriteLock ( It . IsAny < IDatabase > ( ) , timeout , Constants . Locks . Languages ) , Times . Once ) ;
}
[Test]
public void ReadLock_Acquired_Only_Once_Per_Key ( )
{
var scopeProvider = GetScopeProvider ( out var syntaxProviderMock ) ;
2021-09-13 21:09:47 +10:00
using ( var outerScope = ( Scope ) scopeProvider . CreateScope ( ) )
2021-03-02 10:53:10 +01:00
{
2021-09-13 21:09:47 +10:00
outerScope . EagerReadLock ( Constants . Locks . Domains ) ;
outerScope . EagerReadLock ( Constants . Locks . Languages ) ;
2021-03-02 10:53:10 +01:00
2021-09-13 21:09:47 +10:00
using ( var innerScope1 = ( Scope ) scopeProvider . CreateScope ( ) )
2021-03-02 10:53:10 +01:00
{
2021-09-13 21:09:47 +10:00
innerScope1 . EagerReadLock ( Constants . Locks . Domains ) ;
innerScope1 . EagerReadLock ( Constants . Locks . Languages ) ;
2021-03-02 10:53:10 +01:00
2021-09-13 21:09:47 +10:00
using ( var innerScope2 = ( Scope ) scopeProvider . CreateScope ( ) )
2021-03-02 10:53:10 +01:00
{
2021-09-13 21:09:47 +10:00
innerScope2 . EagerReadLock ( Constants . Locks . Domains ) ;
innerScope2 . EagerReadLock ( Constants . Locks . Languages ) ;
2021-03-02 10:53:10 +01:00
innerScope2 . Complete ( ) ;
}
innerScope1 . Complete ( ) ;
}
outerScope . Complete ( ) ;
}
syntaxProviderMock . Verify ( x = > x . ReadLock ( It . IsAny < IDatabase > ( ) , Constants . Locks . Domains ) , Times . Once ) ;
syntaxProviderMock . Verify ( x = > x . ReadLock ( It . IsAny < IDatabase > ( ) , Constants . Locks . Languages ) , Times . Once ) ;
}
[Test]
public void ReadLock_With_Timeout_Acquired_Only_Once_Per_Key ( )
{
var scopeProvider = GetScopeProvider ( out var syntaxProviderMock ) ;
var timeOut = TimeSpan . FromMilliseconds ( 10000 ) ;
2021-09-13 21:09:47 +10:00
using ( var outerScope = ( Scope ) scopeProvider . CreateScope ( ) )
2021-03-02 10:53:10 +01:00
{
2021-09-13 21:09:47 +10:00
outerScope . EagerReadLock ( timeOut , Constants . Locks . Domains ) ;
outerScope . EagerReadLock ( timeOut , Constants . Locks . Languages ) ;
2021-03-02 10:53:10 +01:00
2021-09-13 21:09:47 +10:00
using ( var innerScope1 = ( Scope ) scopeProvider . CreateScope ( ) )
2021-03-02 10:53:10 +01:00
{
2021-09-13 21:09:47 +10:00
innerScope1 . EagerReadLock ( timeOut , Constants . Locks . Domains ) ;
innerScope1 . EagerReadLock ( timeOut , Constants . Locks . Languages ) ;
2021-03-02 10:53:10 +01:00
2021-09-13 21:09:47 +10:00
using ( var innerScope2 = ( Scope ) scopeProvider . CreateScope ( ) )
2021-03-02 10:53:10 +01:00
{
2021-09-13 21:09:47 +10:00
innerScope2 . EagerReadLock ( timeOut , Constants . Locks . Domains ) ;
innerScope2 . EagerReadLock ( timeOut , Constants . Locks . Languages ) ;
2021-03-02 10:53:10 +01:00
innerScope2 . Complete ( ) ;
}
innerScope1 . Complete ( ) ;
}
outerScope . Complete ( ) ;
}
syntaxProviderMock . Verify ( x = > x . ReadLock ( It . IsAny < IDatabase > ( ) , timeOut , Constants . Locks . Domains ) , Times . Once ) ;
syntaxProviderMock . Verify ( x = > x . ReadLock ( It . IsAny < IDatabase > ( ) , timeOut , Constants . Locks . Languages ) , Times . Once ) ;
}
2021-03-12 13:30:25 +01:00
[Test]
public void ReadLock_Acquired_Only_Once_When_InnerScope_Disposed ( )
{
var scopeProvider = GetScopeProvider ( out var syntaxProviderMock ) ;
using ( var outerScope = scopeProvider . CreateScope ( ) )
{
outerScope . ReadLock ( Constants . Locks . Languages ) ;
2021-09-13 21:09:47 +10:00
using ( var innerScope = ( Scope ) scopeProvider . CreateScope ( ) )
2021-03-12 13:30:25 +01:00
{
2021-09-13 21:09:47 +10:00
innerScope . EagerReadLock ( Constants . Locks . Languages ) ;
innerScope . EagerReadLock ( Constants . Locks . ContentTree ) ;
2021-03-12 13:30:25 +01:00
innerScope . Complete ( ) ;
}
outerScope . ReadLock ( Constants . Locks . ContentTree ) ;
outerScope . Complete ( ) ;
}
2021-03-15 08:38:23 +01:00
syntaxProviderMock . Verify ( x = > x . ReadLock ( It . IsAny < IDatabase > ( ) , Constants . Locks . Languages ) , Times . Once ) ;
syntaxProviderMock . Verify ( x = > x . ReadLock ( It . IsAny < IDatabase > ( ) , Constants . Locks . ContentTree ) , Times . Once ) ;
2021-03-12 13:30:25 +01:00
}
2021-03-02 12:55:18 +01:00
[Test]
public void WriteLocks_Count_correctly_If_Lock_Requested_Twice_In_Scope ( )
{
var scopeProvider = GetScopeProvider ( out var syntaxProviderMock ) ;
2021-03-12 13:10:17 +01:00
Guid innerscopeId ;
2021-03-02 12:55:18 +01:00
2021-09-13 21:09:47 +10:00
using ( var outerscope = ( Scope ) scopeProvider . CreateScope ( ) )
2021-03-02 12:55:18 +01:00
{
2021-09-13 21:09:47 +10:00
outerscope . EagerWriteLock ( Constants . Locks . ContentTree ) ;
outerscope . EagerWriteLock ( Constants . Locks . ContentTree ) ;
Assert . AreEqual ( 2 , outerscope . GetWriteLocks ( ) [ outerscope . InstanceId ] [ Constants . Locks . ContentTree ] ) ;
2021-03-02 12:55:18 +01:00
2021-09-13 21:09:47 +10:00
using ( var innerScope = ( Scope ) scopeProvider . CreateScope ( ) )
2021-03-02 12:55:18 +01:00
{
2021-03-12 13:10:17 +01:00
innerscopeId = innerScope . InstanceId ;
2021-09-13 21:09:47 +10:00
innerScope . EagerWriteLock ( Constants . Locks . ContentTree ) ;
innerScope . EagerWriteLock ( Constants . Locks . ContentTree ) ;
Assert . AreEqual ( 2 , outerscope . GetWriteLocks ( ) [ outerscope . InstanceId ] [ Constants . Locks . ContentTree ] ) ;
Assert . AreEqual ( 2 , outerscope . GetWriteLocks ( ) [ innerscopeId ] [ Constants . Locks . ContentTree ] ) ;
innerScope . EagerWriteLock ( Constants . Locks . Languages ) ;
innerScope . EagerWriteLock ( Constants . Locks . Languages ) ;
Assert . AreEqual ( 2 , outerscope . GetWriteLocks ( ) [ innerScope . InstanceId ] [ Constants . Locks . Languages ] ) ;
2021-03-02 12:55:18 +01:00
innerScope . Complete ( ) ;
}
2021-09-13 21:09:47 +10:00
Assert . AreEqual ( 2 , outerscope . GetWriteLocks ( ) [ outerscope . InstanceId ] [ Constants . Locks . ContentTree ] ) ;
Assert . IsFalse ( outerscope . GetWriteLocks ( ) . ContainsKey ( innerscopeId ) ) ;
2021-03-02 12:55:18 +01:00
outerscope . Complete ( ) ;
}
}
[Test]
public void ReadLocks_Count_correctly_If_Lock_Requested_Twice_In_Scope ( )
{
var scopeProvider = GetScopeProvider ( out var syntaxProviderMock ) ;
2021-03-12 13:10:17 +01:00
Guid innerscopeId ;
2021-03-02 12:55:18 +01:00
2021-09-13 21:09:47 +10:00
using ( var outerscope = ( Scope ) scopeProvider . CreateScope ( ) )
2021-03-02 12:55:18 +01:00
{
2021-09-13 21:09:47 +10:00
outerscope . EagerReadLock ( Constants . Locks . ContentTree ) ;
outerscope . EagerReadLock ( Constants . Locks . ContentTree ) ;
Assert . AreEqual ( 2 , outerscope . GetReadLocks ( ) [ outerscope . InstanceId ] [ Constants . Locks . ContentTree ] ) ;
2021-03-02 12:55:18 +01:00
2021-09-13 21:09:47 +10:00
using ( var innerScope = ( Scope ) scopeProvider . CreateScope ( ) )
2021-03-02 12:55:18 +01:00
{
2021-03-12 13:10:17 +01:00
innerscopeId = innerScope . InstanceId ;
2021-09-13 21:09:47 +10:00
innerScope . EagerReadLock ( Constants . Locks . ContentTree ) ;
innerScope . EagerReadLock ( Constants . Locks . ContentTree ) ;
Assert . AreEqual ( 2 , outerscope . GetReadLocks ( ) [ outerscope . InstanceId ] [ Constants . Locks . ContentTree ] ) ;
Assert . AreEqual ( 2 , outerscope . GetReadLocks ( ) [ innerScope . InstanceId ] [ Constants . Locks . ContentTree ] ) ;
innerScope . EagerReadLock ( Constants . Locks . Languages ) ;
innerScope . EagerReadLock ( Constants . Locks . Languages ) ;
Assert . AreEqual ( 2 , outerscope . GetReadLocks ( ) [ innerScope . InstanceId ] [ Constants . Locks . Languages ] ) ;
2021-03-02 12:55:18 +01:00
innerScope . Complete ( ) ;
}
2021-09-13 21:09:47 +10:00
Assert . AreEqual ( 2 , outerscope . GetReadLocks ( ) [ outerscope . InstanceId ] [ Constants . Locks . ContentTree ] ) ;
Assert . IsFalse ( outerscope . GetReadLocks ( ) . ContainsKey ( innerscopeId ) ) ;
2021-03-15 08:38:23 +01:00
2021-03-02 12:55:18 +01:00
outerscope . Complete ( ) ;
}
}
2021-03-02 10:53:10 +01:00
[Test]
public void Nested_Scopes_WriteLocks_Count_Correctly ( )
{
var scopeProvider = GetScopeProvider ( out var syntaxProviderMock ) ;
2021-03-12 13:10:17 +01:00
Guid innerScope1Id , innerScope2Id ;
2021-03-02 10:53:10 +01:00
2021-03-12 13:10:17 +01:00
using ( var parentScope = scopeProvider . CreateScope ( ) )
2021-03-02 10:53:10 +01:00
{
2021-09-13 21:09:47 +10:00
var realParentScope = ( Scope ) parentScope ;
2021-03-12 13:10:17 +01:00
parentScope . WriteLock ( Constants . Locks . ContentTree ) ;
parentScope . WriteLock ( Constants . Locks . ContentTypes ) ;
2021-03-02 10:53:10 +01:00
2021-09-13 21:09:47 +10:00
Assert . AreEqual ( 1 , realParentScope . GetWriteLocks ( ) [ realParentScope . InstanceId ] [ Constants . Locks . ContentTree ] , $"parentScope after locks acquired: {nameof(Constants.Locks.ContentTree)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetWriteLocks ( ) [ realParentScope . InstanceId ] [ Constants . Locks . ContentTypes ] , $"parentScope after locks acquired: {nameof(Constants.Locks.ContentTypes)}" ) ;
2021-03-02 10:53:10 +01:00
using ( var innerScope1 = scopeProvider . CreateScope ( ) )
{
2021-03-12 13:10:17 +01:00
innerScope1Id = innerScope1 . InstanceId ;
2021-03-02 10:53:10 +01:00
innerScope1 . WriteLock ( Constants . Locks . ContentTree ) ;
innerScope1 . WriteLock ( Constants . Locks . ContentTypes ) ;
innerScope1 . WriteLock ( Constants . Locks . Languages ) ;
2021-09-13 21:09:47 +10:00
Assert . AreEqual ( 1 , realParentScope . GetWriteLocks ( ) [ realParentScope . InstanceId ] [ Constants . Locks . ContentTree ] , $"innerScope1, parent instance, after locks acquired: {nameof(Constants.Locks.ContentTree)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetWriteLocks ( ) [ realParentScope . InstanceId ] [ Constants . Locks . ContentTypes ] , $"innerScope1, parent instance, after locks acquired: {nameof(Constants.Locks.ContentTypes)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetWriteLocks ( ) [ innerScope1 . InstanceId ] [ Constants . Locks . ContentTree ] , $"innerScope1, innerScope1 instance, after locks acquired: {nameof(Constants.Locks.ContentTree)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetWriteLocks ( ) [ innerScope1 . InstanceId ] [ Constants . Locks . ContentTypes ] , $"innerScope1, innerScope1 instance, after locks acquired: {nameof(Constants.Locks.ContentTypes)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetWriteLocks ( ) [ innerScope1 . InstanceId ] [ Constants . Locks . Languages ] , $"innerScope1, innerScope1 instance, after locks acquired: {nameof(Constants.Locks.Languages)}" ) ;
2021-03-02 10:53:10 +01:00
using ( var innerScope2 = scopeProvider . CreateScope ( ) )
{
2021-03-12 13:10:17 +01:00
innerScope2Id = innerScope2 . InstanceId ;
2021-03-02 10:53:10 +01:00
innerScope2 . WriteLock ( Constants . Locks . ContentTree ) ;
innerScope2 . WriteLock ( Constants . Locks . MediaTypes ) ;
2021-09-13 21:09:47 +10:00
Assert . AreEqual ( 1 , realParentScope . GetWriteLocks ( ) [ realParentScope . InstanceId ] [ Constants . Locks . ContentTree ] , $"innerScope2, parent instance, after locks acquired: {nameof(Constants.Locks.ContentTree)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetWriteLocks ( ) [ realParentScope . InstanceId ] [ Constants . Locks . ContentTypes ] , $"innerScope2, parent instance, after locks acquired: {nameof(Constants.Locks.ContentTypes)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetWriteLocks ( ) [ innerScope1 . InstanceId ] [ Constants . Locks . ContentTree ] , $"innerScope2, innerScope1 instance, after locks acquired: {nameof(Constants.Locks.ContentTree)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetWriteLocks ( ) [ innerScope1 . InstanceId ] [ Constants . Locks . ContentTypes ] , $"innerScope2, innerScope1 instance, after locks acquired: {nameof(Constants.Locks.ContentTypes)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetWriteLocks ( ) [ innerScope1 . InstanceId ] [ Constants . Locks . Languages ] , $"innerScope2, innerScope1 instance, after locks acquired: {nameof(Constants.Locks.Languages)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetWriteLocks ( ) [ innerScope2 . InstanceId ] [ Constants . Locks . ContentTree ] , $"innerScope2, innerScope2 instance, after locks acquired: {nameof(Constants.Locks.ContentTree)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetWriteLocks ( ) [ innerScope2 . InstanceId ] [ Constants . Locks . MediaTypes ] , $"innerScope2, innerScope2 instance, after locks acquired: {nameof(Constants.Locks.MediaTypes)}" ) ;
2021-03-02 10:53:10 +01:00
innerScope2 . Complete ( ) ;
}
2021-09-13 21:09:47 +10:00
Assert . AreEqual ( 1 , realParentScope . GetWriteLocks ( ) [ realParentScope . InstanceId ] [ Constants . Locks . ContentTree ] , $"innerScope1, parent instance, after innserScope2 disposed: {nameof(Constants.Locks.ContentTree)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetWriteLocks ( ) [ realParentScope . InstanceId ] [ Constants . Locks . ContentTypes ] , $"innerScope1, parent instance, after innserScope2 disposed: {nameof(Constants.Locks.ContentTypes)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetWriteLocks ( ) [ innerScope1 . InstanceId ] [ Constants . Locks . ContentTree ] , $"innerScope1, innerScope1 instance, after innserScope2 disposed: {nameof(Constants.Locks.ContentTree)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetWriteLocks ( ) [ innerScope1 . InstanceId ] [ Constants . Locks . ContentTypes ] , $"innerScope1, innerScope1 instance, after innserScope2 disposed: {nameof(Constants.Locks.ContentTypes)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetWriteLocks ( ) [ innerScope1 . InstanceId ] [ Constants . Locks . Languages ] , $"innerScope1, innerScope1 instance, after innserScope2 disposed: {nameof(Constants.Locks.Languages)}" ) ;
Assert . IsFalse ( realParentScope . GetWriteLocks ( ) . ContainsKey ( innerScope2Id ) ) ;
2021-03-02 10:53:10 +01:00
innerScope1 . Complete ( ) ;
}
2021-09-13 21:09:47 +10:00
Assert . AreEqual ( 1 , realParentScope . GetWriteLocks ( ) [ realParentScope . InstanceId ] [ Constants . Locks . ContentTree ] , $"parentScope after inner scopes disposed: {nameof(Constants.Locks.ContentTree)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetWriteLocks ( ) [ realParentScope . InstanceId ] [ Constants . Locks . ContentTypes ] , $"parentScope after inner scopes disposed: {nameof(Constants.Locks.ContentTypes)}" ) ;
Assert . IsFalse ( realParentScope . GetWriteLocks ( ) . ContainsKey ( innerScope2Id ) ) ;
Assert . IsFalse ( realParentScope . GetWriteLocks ( ) . ContainsKey ( innerScope1Id ) ) ;
2021-03-02 10:53:10 +01:00
2021-03-12 13:10:17 +01:00
parentScope . Complete ( ) ;
2021-03-02 10:53:10 +01:00
}
}
[Test]
public void Nested_Scopes_ReadLocks_Count_Correctly ( )
{
var scopeProvider = GetScopeProvider ( out var syntaxProviderMock ) ;
2021-03-12 13:10:17 +01:00
Guid innerScope1Id , innerScope2Id ;
2021-03-02 10:53:10 +01:00
2021-03-12 13:10:17 +01:00
using ( var parentScope = scopeProvider . CreateScope ( ) )
2021-03-02 10:53:10 +01:00
{
2021-09-13 21:09:47 +10:00
var realParentScope = ( Scope ) parentScope ;
2021-03-12 13:10:17 +01:00
parentScope . ReadLock ( Constants . Locks . ContentTree ) ;
parentScope . ReadLock ( Constants . Locks . ContentTypes ) ;
2021-09-13 21:09:47 +10:00
Assert . AreEqual ( 1 , realParentScope . GetReadLocks ( ) [ realParentScope . InstanceId ] [ Constants . Locks . ContentTree ] , $"parentScope after locks acquired: {nameof(Constants.Locks.ContentTree)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetReadLocks ( ) [ realParentScope . InstanceId ] [ Constants . Locks . ContentTypes ] , $"parentScope after locks acquired: {nameof(Constants.Locks.ContentTypes)}" ) ;
2021-03-02 10:53:10 +01:00
using ( var innserScope1 = scopeProvider . CreateScope ( ) )
{
2021-03-12 13:10:17 +01:00
innerScope1Id = innserScope1 . InstanceId ;
2021-03-02 10:53:10 +01:00
innserScope1 . ReadLock ( Constants . Locks . ContentTree ) ;
innserScope1 . ReadLock ( Constants . Locks . ContentTypes ) ;
innserScope1 . ReadLock ( Constants . Locks . Languages ) ;
2021-09-13 21:09:47 +10:00
Assert . AreEqual ( 1 , realParentScope . GetReadLocks ( ) [ realParentScope . InstanceId ] [ Constants . Locks . ContentTree ] , $"innerScope1, parent instance, after locks acquired: {nameof(Constants.Locks.ContentTree)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetReadLocks ( ) [ realParentScope . InstanceId ] [ Constants . Locks . ContentTypes ] , $"innerScope1, parent instance, after locks acquired: {nameof(Constants.Locks.ContentTypes)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetReadLocks ( ) [ innserScope1 . InstanceId ] [ Constants . Locks . ContentTree ] , $"innerScope1, innerScope1 instance, after locks acquired: {nameof(Constants.Locks.ContentTree)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetReadLocks ( ) [ innserScope1 . InstanceId ] [ Constants . Locks . ContentTypes ] , $"innerScope1, innerScope1 instance, after locks acquired: {nameof(Constants.Locks.ContentTypes)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetReadLocks ( ) [ innserScope1 . InstanceId ] [ Constants . Locks . Languages ] , $"innerScope1, innerScope1 instance, after locks acquired: {nameof(Constants.Locks.Languages)}" ) ;
2021-03-02 10:53:10 +01:00
using ( var innerScope2 = scopeProvider . CreateScope ( ) )
{
2021-03-12 13:10:17 +01:00
innerScope2Id = innerScope2 . InstanceId ;
2021-03-02 10:53:10 +01:00
innerScope2 . ReadLock ( Constants . Locks . ContentTree ) ;
innerScope2 . ReadLock ( Constants . Locks . MediaTypes ) ;
2021-09-13 21:09:47 +10:00
Assert . AreEqual ( 1 , realParentScope . GetReadLocks ( ) [ realParentScope . InstanceId ] [ Constants . Locks . ContentTree ] , $"innerScope2, parent instance, after locks acquired: {nameof(Constants.Locks.ContentTree)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetReadLocks ( ) [ realParentScope . InstanceId ] [ Constants . Locks . ContentTypes ] , $"innerScope2, parent instance, after locks acquired: {nameof(Constants.Locks.ContentTypes)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetReadLocks ( ) [ innserScope1 . InstanceId ] [ Constants . Locks . ContentTree ] , $"innerScope2, innerScope1 instance, after locks acquired: {nameof(Constants.Locks.ContentTree)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetReadLocks ( ) [ innserScope1 . InstanceId ] [ Constants . Locks . ContentTypes ] , $"innerScope2, innerScope1 instance, after locks acquired: {nameof(Constants.Locks.ContentTypes)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetReadLocks ( ) [ innserScope1 . InstanceId ] [ Constants . Locks . Languages ] , $"innerScope2, innerScope1 instance, after locks acquired: {nameof(Constants.Locks.Languages)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetReadLocks ( ) [ innerScope2 . InstanceId ] [ Constants . Locks . ContentTree ] , $"innerScope2, innerScope2 instance, after locks acquired: {nameof(Constants.Locks.ContentTree)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetReadLocks ( ) [ innerScope2 . InstanceId ] [ Constants . Locks . MediaTypes ] , $"innerScope2, innerScope2 instance, after locks acquired: {nameof(Constants.Locks.MediaTypes)}" ) ;
2021-03-02 10:53:10 +01:00
innerScope2 . Complete ( ) ;
}
2021-03-12 13:10:17 +01:00
2021-09-13 21:09:47 +10:00
Assert . AreEqual ( 1 , realParentScope . GetReadLocks ( ) [ realParentScope . InstanceId ] [ Constants . Locks . ContentTree ] , $"innerScope1, parent instance, after innerScope2 disposed: {nameof(Constants.Locks.ContentTree)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetReadLocks ( ) [ realParentScope . InstanceId ] [ Constants . Locks . ContentTypes ] , $"innerScope1, parent instance, after innerScope2 disposed: {nameof(Constants.Locks.ContentTypes)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetReadLocks ( ) [ innserScope1 . InstanceId ] [ Constants . Locks . ContentTree ] , $"innerScope1, innerScope1 instance, after innerScope2 disposed: {nameof(Constants.Locks.ContentTree)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetReadLocks ( ) [ innserScope1 . InstanceId ] [ Constants . Locks . ContentTypes ] , $"innerScope1, innerScope1 instance, after innerScope2 disposed: {nameof(Constants.Locks.ContentTypes)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetReadLocks ( ) [ innserScope1 . InstanceId ] [ Constants . Locks . Languages ] , $"innerScope1, innerScope1 instance, after innerScope2 disposed: {nameof(Constants.Locks.Languages)}" ) ;
Assert . IsFalse ( realParentScope . GetReadLocks ( ) . ContainsKey ( innerScope2Id ) ) ;
2021-03-02 10:53:10 +01:00
innserScope1 . Complete ( ) ;
}
2021-09-13 21:09:47 +10:00
Assert . AreEqual ( 1 , realParentScope . GetReadLocks ( ) [ realParentScope . InstanceId ] [ Constants . Locks . ContentTree ] , $"parentScope after innerScope1 disposed: {nameof(Constants.Locks.ContentTree)}" ) ;
Assert . AreEqual ( 1 , realParentScope . GetReadLocks ( ) [ realParentScope . InstanceId ] [ Constants . Locks . ContentTypes ] , $"parentScope after innerScope1 disposed: {nameof(Constants.Locks.ContentTypes)}" ) ;
Assert . IsFalse ( realParentScope . GetReadLocks ( ) . ContainsKey ( innerScope2Id ) ) ;
Assert . IsFalse ( realParentScope . GetReadLocks ( ) . ContainsKey ( innerScope1Id ) ) ;
2021-03-12 13:10:17 +01:00
parentScope . Complete ( ) ;
2021-03-02 10:53:10 +01:00
}
}
2021-03-12 13:30:25 +01:00
[Test]
public void WriteLock_Doesnt_Increment_On_Error ( )
{
var scopeProvider = GetScopeProvider ( out var syntaxProviderMock ) ;
syntaxProviderMock . Setup ( x = > x . WriteLock ( It . IsAny < IDatabase > ( ) , It . IsAny < int [ ] > ( ) ) ) . Throws ( new Exception ( "Boom" ) ) ;
2021-09-13 21:09:47 +10:00
using ( var scope = ( Scope ) scopeProvider . CreateScope ( ) )
2021-03-12 13:30:25 +01:00
{
2021-09-13 21:09:47 +10:00
Assert . Throws < Exception > ( ( ) = > scope . EagerWriteLock ( Constants . Locks . Languages ) ) ;
Assert . IsFalse ( scope . GetWriteLocks ( ) [ scope . InstanceId ] . ContainsKey ( Constants . Locks . Languages ) ) ;
2021-03-12 13:30:25 +01:00
scope . Complete ( ) ;
}
}
[Test]
public void ReadLock_Doesnt_Increment_On_Error ( )
{
var scopeProvider = GetScopeProvider ( out var syntaxProviderMock ) ;
syntaxProviderMock . Setup ( x = > x . ReadLock ( It . IsAny < IDatabase > ( ) , It . IsAny < int [ ] > ( ) ) ) . Throws ( new Exception ( "Boom" ) ) ;
2021-09-13 21:09:47 +10:00
using ( var scope = ( Scope ) scopeProvider . CreateScope ( ) )
2021-03-12 13:30:25 +01:00
{
2021-09-13 21:09:47 +10:00
Assert . Throws < Exception > ( ( ) = > scope . EagerReadLock ( Constants . Locks . Languages ) ) ;
Assert . IsFalse ( scope . GetReadLocks ( ) [ scope . InstanceId ] . ContainsKey ( Constants . Locks . Languages ) ) ;
2021-03-12 13:30:25 +01:00
scope . Complete ( ) ;
}
}
2021-03-15 08:54:52 +01:00
[Test]
public void Scope_Throws_If_ReadLocks_Not_Cleared ( )
{
var scopeprovider = GetScopeProvider ( out var syntaxProviderMock ) ;
2021-09-13 21:09:47 +10:00
var scope = ( Scope ) scopeprovider . CreateScope ( ) ;
2021-03-15 08:54:52 +01:00
2021-03-17 13:09:45 +01:00
try
{
// Request a lock to create the ReadLocks dict.
scope . ReadLock ( Constants . Locks . Domains ) ;
2021-03-15 08:54:52 +01:00
2021-03-17 13:09:45 +01:00
var readDict = new Dictionary < int , int > ( ) ;
readDict [ Constants . Locks . Languages ] = 1 ;
2021-09-13 21:09:47 +10:00
scope . GetReadLocks ( ) [ Guid . NewGuid ( ) ] = readDict ;
2021-03-15 08:54:52 +01:00
2021-03-17 13:09:45 +01:00
Assert . Throws < InvalidOperationException > ( ( ) = > scope . Dispose ( ) ) ;
}
finally
{
// We have to clear so we can properly dispose the scope, otherwise it'll mess with other tests.
2021-09-13 21:09:47 +10:00
scope . GetReadLocks ( ) ? . Clear ( ) ;
2021-03-17 13:09:45 +01:00
scope . Dispose ( ) ;
}
2021-03-15 08:54:52 +01:00
}
[Test]
public void Scope_Throws_If_WriteLocks_Not_Cleared ( )
{
var scopeprovider = GetScopeProvider ( out var syntaxProviderMock ) ;
2021-09-13 21:09:47 +10:00
var scope = ( Scope ) scopeprovider . CreateScope ( ) ;
2021-03-15 08:54:52 +01:00
2021-03-17 13:09:45 +01:00
try
{
2021-03-18 11:24:14 +01:00
// Request a lock to create the WriteLocks dict.
2021-03-17 13:09:45 +01:00
scope . WriteLock ( Constants . Locks . Domains ) ;
var writeDict = new Dictionary < int , int > ( ) ;
writeDict [ Constants . Locks . Languages ] = 1 ;
2021-09-13 21:09:47 +10:00
scope . GetWriteLocks ( ) [ Guid . NewGuid ( ) ] = writeDict ;
2021-03-15 08:54:52 +01:00
2021-03-17 13:09:45 +01:00
Assert . Throws < InvalidOperationException > ( ( ) = > scope . Dispose ( ) ) ;
}
finally
{
// We have to clear so we can properly dispose the scope, otherwise it'll mess with other tests.
2021-09-13 21:09:47 +10:00
scope . GetWriteLocks ( ) ? . Clear ( ) ;
2021-03-17 13:09:45 +01:00
scope . Dispose ( ) ;
}
}
2021-03-15 08:54:52 +01:00
2021-03-17 13:09:45 +01:00
[Test]
public void WriteLocks_Not_Created_Until_First_Lock ( )
{
var scopeProvider = GetScopeProvider ( out var syntaxProviderMock ) ;
using ( var scope = scopeProvider . CreateScope ( ) )
{
2021-09-13 21:09:47 +10:00
var realScope = ( Scope ) scope ;
Assert . IsNull ( realScope . GetWriteLocks ( ) ) ;
2021-03-17 13:09:45 +01:00
}
}
[Test]
public void ReadLocks_Not_Created_Until_First_Lock ( )
{
var scopeProvider = GetScopeProvider ( out var syntaxProviderMock ) ;
using ( var scope = scopeProvider . CreateScope ( ) )
{
2021-09-13 21:09:47 +10:00
var realScope = ( Scope ) scope ;
Assert . IsNull ( realScope . GetReadLocks ( ) ) ;
2021-03-17 13:09:45 +01:00
}
2021-03-15 08:54:52 +01:00
}
2021-03-02 10:53:10 +01:00
}
}