Files
Umbraco-CMS/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Scoping/ScopeUnitTests.cs

570 lines
31 KiB
C#
Raw Normal View History

2021-03-02 10:53:10 +01:00
using System;
using System.Collections.Generic;
using System.Linq;
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;
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;
Netcore: File systems rework (#10181) * Allow IMediaFileSystem to be replace in the DI, or registered with inner filesystem * Remove GetFileSystem from Filesystems It was only used by tests. * Make MediaFileSystem inherit from PhysicalFileSystem directly * Remove FileSystemWrapper * Remove inner filesystem from MediaFileSystem * Add MediaFileManager and bare minimum to make it testable * Remove MediaFileSystem * Fix unit tests using MediaFileManager * Remove IFileSystem and rely only on FileSystem * Hide dangerous methods in FileSystems and do some cleaning * Apply stylecop warnings to MediaFileManager * Add FilesystemsCreator to Tests.Common This allows you to create an instance if FileSystems with your own specified IFileSystem for testing purposes outside our own test suite. * Allow the stylesheet filesystem to be replaced. * Fix tests * Don't save stylesheetWrapper in a temporary var * refactor(FileSystems): change how stylesheet filesystem is registered * fix(FileSystems): unable to overwrite media filesystem SetMediaFileSystem added the MediaManager as a Singleton instead of replacing the existing instance. * fix(FileSystems): calling AddFileSystems replaces MediaManager When calling AddFileSystems after SetMediaFileSystem the MediaManager gets replaced by the default PhysicalFileSystem, so instead of calling SetMediaFileSystem in AddFileSystems we now call TrySetMediaFileSystem instead. This method will not replace any existing instance of the MediaManager if there's already a MediaManager registered. * Use SetMediaFileSystem instead of TrySet, and rename AddFilesystems to ConfigureFileSystems Also don't call AddFileSystems again in ConfigureFilesystems * Don't wrap CSS filesystem twice * Add CreateShadowWrapperInternal to avoid casting * Throw UnauthorizedAccessException isntead of InvalidOperationException * Remove ResetShadowId Co-authored-by: Rasmus John Pedersen <mail@rjp.dk>
2021-04-27 09:52:17 +02:00
using Umbraco.Cms.Core.Strings;
using Umbraco.Cms.Infrastructure.Persistence;
using Umbraco.Cms.Infrastructure.Persistence.SqlSyntax;
2021-03-02 10:53:10 +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>
private ScopeProvider GetScopeProvider(out Mock<ISqlSyntaxProvider> syntaxProviderMock)
2021-03-02 10:53:10 +01:00
{
var loggerFactory = NullLoggerFactory.Instance;
Netcore: File systems rework (#10181) * Allow IMediaFileSystem to be replace in the DI, or registered with inner filesystem * Remove GetFileSystem from Filesystems It was only used by tests. * Make MediaFileSystem inherit from PhysicalFileSystem directly * Remove FileSystemWrapper * Remove inner filesystem from MediaFileSystem * Add MediaFileManager and bare minimum to make it testable * Remove MediaFileSystem * Fix unit tests using MediaFileManager * Remove IFileSystem and rely only on FileSystem * Hide dangerous methods in FileSystems and do some cleaning * Apply stylecop warnings to MediaFileManager * Add FilesystemsCreator to Tests.Common This allows you to create an instance if FileSystems with your own specified IFileSystem for testing purposes outside our own test suite. * Allow the stylesheet filesystem to be replaced. * Fix tests * Don't save stylesheetWrapper in a temporary var * refactor(FileSystems): change how stylesheet filesystem is registered * fix(FileSystems): unable to overwrite media filesystem SetMediaFileSystem added the MediaManager as a Singleton instead of replacing the existing instance. * fix(FileSystems): calling AddFileSystems replaces MediaManager When calling AddFileSystems after SetMediaFileSystem the MediaManager gets replaced by the default PhysicalFileSystem, so instead of calling SetMediaFileSystem in AddFileSystems we now call TrySetMediaFileSystem instead. This method will not replace any existing instance of the MediaManager if there's already a MediaManager registered. * Use SetMediaFileSystem instead of TrySet, and rename AddFilesystems to ConfigureFileSystems Also don't call AddFileSystems again in ConfigureFilesystems * Don't wrap CSS filesystem twice * Add CreateShadowWrapperInternal to avoid casting * Throw UnauthorizedAccessException isntead of InvalidOperationException * Remove ResetShadowId Co-authored-by: Rasmus John Pedersen <mail@rjp.dk>
2021-04-27 09:52:17 +02:00
var fileSystems = new FileSystems(loggerFactory,
Mock.Of<IIOHelper>(), Mock.Of<IOptions<GlobalSettings>>(), Mock.Of<IHostingEnvironment>());
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>();
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);
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);
return new ScopeProvider(
databaseFactory.Object,
Netcore: File systems rework (#10181) * Allow IMediaFileSystem to be replace in the DI, or registered with inner filesystem * Remove GetFileSystem from Filesystems It was only used by tests. * Make MediaFileSystem inherit from PhysicalFileSystem directly * Remove FileSystemWrapper * Remove inner filesystem from MediaFileSystem * Add MediaFileManager and bare minimum to make it testable * Remove MediaFileSystem * Fix unit tests using MediaFileManager * Remove IFileSystem and rely only on FileSystem * Hide dangerous methods in FileSystems and do some cleaning * Apply stylecop warnings to MediaFileManager * Add FilesystemsCreator to Tests.Common This allows you to create an instance if FileSystems with your own specified IFileSystem for testing purposes outside our own test suite. * Allow the stylesheet filesystem to be replaced. * Fix tests * Don't save stylesheetWrapper in a temporary var * refactor(FileSystems): change how stylesheet filesystem is registered * fix(FileSystems): unable to overwrite media filesystem SetMediaFileSystem added the MediaManager as a Singleton instead of replacing the existing instance. * fix(FileSystems): calling AddFileSystems replaces MediaManager When calling AddFileSystems after SetMediaFileSystem the MediaManager gets replaced by the default PhysicalFileSystem, so instead of calling SetMediaFileSystem in AddFileSystems we now call TrySetMediaFileSystem instead. This method will not replace any existing instance of the MediaManager if there's already a MediaManager registered. * Use SetMediaFileSystem instead of TrySet, and rename AddFilesystems to ConfigureFileSystems Also don't call AddFileSystems again in ConfigureFilesystems * Don't wrap CSS filesystem twice * Add CreateShadowWrapperInternal to avoid casting * Throw UnauthorizedAccessException isntead of InvalidOperationException * Remove ResetShadowId Co-authored-by: Rasmus John Pedersen <mail@rjp.dk>
2021-04-27 09:52:17 +02:00
fileSystems,
Options.Create(new CoreDebugSettings()),
Netcore: File systems rework (#10181) * Allow IMediaFileSystem to be replace in the DI, or registered with inner filesystem * Remove GetFileSystem from Filesystems It was only used by tests. * Make MediaFileSystem inherit from PhysicalFileSystem directly * Remove FileSystemWrapper * Remove inner filesystem from MediaFileSystem * Add MediaFileManager and bare minimum to make it testable * Remove MediaFileSystem * Fix unit tests using MediaFileManager * Remove IFileSystem and rely only on FileSystem * Hide dangerous methods in FileSystems and do some cleaning * Apply stylecop warnings to MediaFileManager * Add FilesystemsCreator to Tests.Common This allows you to create an instance if FileSystems with your own specified IFileSystem for testing purposes outside our own test suite. * Allow the stylesheet filesystem to be replaced. * Fix tests * Don't save stylesheetWrapper in a temporary var * refactor(FileSystems): change how stylesheet filesystem is registered * fix(FileSystems): unable to overwrite media filesystem SetMediaFileSystem added the MediaManager as a Singleton instead of replacing the existing instance. * fix(FileSystems): calling AddFileSystems replaces MediaManager When calling AddFileSystems after SetMediaFileSystem the MediaManager gets replaced by the default PhysicalFileSystem, so instead of calling SetMediaFileSystem in AddFileSystems we now call TrySetMediaFileSystem instead. This method will not replace any existing instance of the MediaManager if there's already a MediaManager registered. * Use SetMediaFileSystem instead of TrySet, and rename AddFilesystems to ConfigureFileSystems Also don't call AddFileSystems again in ConfigureFilesystems * Don't wrap CSS filesystem twice * Add CreateShadowWrapperInternal to avoid casting * Throw UnauthorizedAccessException isntead of InvalidOperationException * Remove ResetShadowId Co-authored-by: Rasmus John Pedersen <mail@rjp.dk>
2021-04-27 09:52:17 +02:00
mediaFileManager,
loggerFactory.CreateLogger<ScopeProvider>(),
loggerFactory,
Mock.Of<IRequestCache>(),
Mock.Of<IEventAggregator>());
2021-03-02 10:53:10 +01:00
}
[Test]
public void Unused_Lazy_Locks_Cleared_At_Child_Scope()
{
var scopeProvider = GetScopeProvider(out var syntaxProviderMock);
var outerScope = scopeProvider.CreateScope();
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);
using (var outerScope = (Scope)scopeProvider.CreateScope())
2021-03-02 10:53:10 +01:00
{
outerScope.EagerWriteLock(Constants.Locks.Domains);
outerScope.EagerWriteLock(Constants.Locks.Languages);
2021-03-02 10:53:10 +01:00
using (var innerScope1 = (Scope)scopeProvider.CreateScope())
2021-03-02 10:53:10 +01:00
{
innerScope1.EagerWriteLock(Constants.Locks.Domains);
innerScope1.EagerWriteLock(Constants.Locks.Languages);
2021-03-02 10:53:10 +01:00
using (var innerScope2 = (Scope)scopeProvider.CreateScope())
2021-03-02 10:53:10 +01: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);
}
[Test]
public void WriteLock_Acquired_Only_Once_When_InnerScope_Disposed()
{
var scopeProvider = GetScopeProvider(out var syntaxProviderMock);
using (var outerScope = (Scope)scopeProvider.CreateScope())
{
outerScope.EagerWriteLock(Constants.Locks.Languages);
using (var innerScope = (Scope)scopeProvider.CreateScope())
{
innerScope.EagerWriteLock(Constants.Locks.Languages);
innerScope.EagerWriteLock(Constants.Locks.ContentTree);
innerScope.Complete();
}
outerScope.EagerWriteLock(Constants.Locks.ContentTree);
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]
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);
using (var outerScope = (Scope)scopeProvider.CreateScope())
2021-03-02 10:53:10 +01:00
{
outerScope.EagerWriteLock(timeout, Constants.Locks.Domains);
outerScope.EagerWriteLock(timeout, Constants.Locks.Languages);
2021-03-02 10:53:10 +01:00
using (var innerScope1 = (Scope)scopeProvider.CreateScope())
2021-03-02 10:53:10 +01:00
{
innerScope1.EagerWriteLock(timeout, Constants.Locks.Domains);
innerScope1.EagerWriteLock(timeout, Constants.Locks.Languages);
2021-03-02 10:53:10 +01:00
using (var innerScope2 = (Scope)scopeProvider.CreateScope())
2021-03-02 10:53:10 +01: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);
using (var outerScope = (Scope)scopeProvider.CreateScope())
2021-03-02 10:53:10 +01:00
{
outerScope.EagerReadLock(Constants.Locks.Domains);
outerScope.EagerReadLock(Constants.Locks.Languages);
2021-03-02 10:53:10 +01:00
using (var innerScope1 = (Scope)scopeProvider.CreateScope())
2021-03-02 10:53:10 +01:00
{
innerScope1.EagerReadLock(Constants.Locks.Domains);
innerScope1.EagerReadLock(Constants.Locks.Languages);
2021-03-02 10:53:10 +01:00
using (var innerScope2 = (Scope)scopeProvider.CreateScope())
2021-03-02 10:53:10 +01: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);
using (var outerScope = (Scope)scopeProvider.CreateScope())
2021-03-02 10:53:10 +01:00
{
outerScope.EagerReadLock(timeOut, Constants.Locks.Domains);
outerScope.EagerReadLock(timeOut, Constants.Locks.Languages);
2021-03-02 10:53:10 +01:00
using (var innerScope1 = (Scope)scopeProvider.CreateScope())
2021-03-02 10:53:10 +01:00
{
innerScope1.EagerReadLock(timeOut, Constants.Locks.Domains);
innerScope1.EagerReadLock(timeOut, Constants.Locks.Languages);
2021-03-02 10:53:10 +01:00
using (var innerScope2 = (Scope)scopeProvider.CreateScope())
2021-03-02 10:53:10 +01: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);
}
[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);
using (var innerScope = (Scope)scopeProvider.CreateScope())
{
innerScope.EagerReadLock(Constants.Locks.Languages);
innerScope.EagerReadLock(Constants.Locks.ContentTree);
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);
}
[Test]
public void WriteLocks_Count_correctly_If_Lock_Requested_Twice_In_Scope()
{
var scopeProvider = GetScopeProvider(out var syntaxProviderMock);
Guid innerscopeId;
using (var outerscope = (Scope)scopeProvider.CreateScope())
{
outerscope.EagerWriteLock(Constants.Locks.ContentTree);
outerscope.EagerWriteLock(Constants.Locks.ContentTree);
Assert.AreEqual(2, outerscope.GetWriteLocks()[outerscope.InstanceId][Constants.Locks.ContentTree]);
using (var innerScope = (Scope)scopeProvider.CreateScope())
{
innerscopeId = innerScope.InstanceId;
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]);
innerScope.Complete();
}
Assert.AreEqual(2, outerscope.GetWriteLocks()[outerscope.InstanceId][Constants.Locks.ContentTree]);
Assert.IsFalse(outerscope.GetWriteLocks().ContainsKey(innerscopeId));
outerscope.Complete();
}
}
[Test]
public void ReadLocks_Count_correctly_If_Lock_Requested_Twice_In_Scope()
{
var scopeProvider = GetScopeProvider(out var syntaxProviderMock);
Guid innerscopeId;
using (var outerscope = (Scope)scopeProvider.CreateScope())
{
outerscope.EagerReadLock(Constants.Locks.ContentTree);
outerscope.EagerReadLock(Constants.Locks.ContentTree);
Assert.AreEqual(2, outerscope.GetReadLocks()[outerscope.InstanceId][Constants.Locks.ContentTree]);
using (var innerScope = (Scope)scopeProvider.CreateScope())
{
innerscopeId = innerScope.InstanceId;
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]);
innerScope.Complete();
}
Assert.AreEqual(2, outerscope.GetReadLocks()[outerscope.InstanceId][Constants.Locks.ContentTree]);
Assert.IsFalse(outerscope.GetReadLocks().ContainsKey(innerscopeId));
2021-03-15 08:38:23 +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);
Guid innerScope1Id, innerScope2Id;
2021-03-02 10:53:10 +01:00
using (var parentScope = scopeProvider.CreateScope())
2021-03-02 10:53:10 +01:00
{
var realParentScope = (Scope)parentScope;
parentScope.WriteLock(Constants.Locks.ContentTree);
parentScope.WriteLock(Constants.Locks.ContentTypes);
2021-03-02 10:53:10 +01: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())
{
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);
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())
{
innerScope2Id = innerScope2.InstanceId;
2021-03-02 10:53:10 +01:00
innerScope2.WriteLock(Constants.Locks.ContentTree);
innerScope2.WriteLock(Constants.Locks.MediaTypes);
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();
}
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();
}
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
parentScope.Complete();
2021-03-02 10:53:10 +01:00
}
}
[Test]
public void Nested_Scopes_ReadLocks_Count_Correctly()
{
var scopeProvider = GetScopeProvider(out var syntaxProviderMock);
Guid innerScope1Id, innerScope2Id;
2021-03-02 10:53:10 +01:00
using (var parentScope = scopeProvider.CreateScope())
2021-03-02 10:53:10 +01:00
{
var realParentScope = (Scope)parentScope;
parentScope.ReadLock(Constants.Locks.ContentTree);
parentScope.ReadLock(Constants.Locks.ContentTypes);
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())
{
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);
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())
{
innerScope2Id = innerScope2.InstanceId;
2021-03-02 10:53:10 +01:00
innerScope2.ReadLock(Constants.Locks.ContentTree);
innerScope2.ReadLock(Constants.Locks.MediaTypes);
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();
}
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();
}
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));
parentScope.Complete();
2021-03-02 10:53:10 +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"));
using (var scope = (Scope)scopeProvider.CreateScope())
{
Assert.Throws<Exception>(() => scope.EagerWriteLock(Constants.Locks.Languages));
Assert.IsFalse(scope.GetWriteLocks()[scope.InstanceId].ContainsKey(Constants.Locks.Languages));
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"));
using (var scope = (Scope)scopeProvider.CreateScope())
{
Assert.Throws<Exception>(() => scope.EagerReadLock(Constants.Locks.Languages));
Assert.IsFalse(scope.GetReadLocks()[scope.InstanceId].ContainsKey(Constants.Locks.Languages));
scope.Complete();
}
}
[Test]
public void Scope_Throws_If_ReadLocks_Not_Cleared()
{
var scopeprovider = GetScopeProvider(out var syntaxProviderMock);
var scope = (Scope)scopeprovider.CreateScope();
try
{
// Request a lock to create the ReadLocks dict.
scope.ReadLock(Constants.Locks.Domains);
var readDict = new Dictionary<int, int>();
readDict[Constants.Locks.Languages] = 1;
scope.GetReadLocks()[Guid.NewGuid()] = readDict;
Assert.Throws<InvalidOperationException>(() => scope.Dispose());
}
finally
{
// We have to clear so we can properly dispose the scope, otherwise it'll mess with other tests.
scope.GetReadLocks()?.Clear();
scope.Dispose();
}
}
[Test]
public void Scope_Throws_If_WriteLocks_Not_Cleared()
{
var scopeprovider = GetScopeProvider(out var syntaxProviderMock);
var scope = (Scope)scopeprovider.CreateScope();
try
{
2021-03-18 11:24:14 +01:00
// Request a lock to create the WriteLocks dict.
scope.WriteLock(Constants.Locks.Domains);
var writeDict = new Dictionary<int, int>();
writeDict[Constants.Locks.Languages] = 1;
scope.GetWriteLocks()[Guid.NewGuid()] = writeDict;
Assert.Throws<InvalidOperationException>(() => scope.Dispose());
}
finally
{
// We have to clear so we can properly dispose the scope, otherwise it'll mess with other tests.
scope.GetWriteLocks()?.Clear();
scope.Dispose();
}
}
[Test]
public void WriteLocks_Not_Created_Until_First_Lock()
{
var scopeProvider = GetScopeProvider(out var syntaxProviderMock);
using (var scope = scopeProvider.CreateScope())
{
var realScope = (Scope)scope;
Assert.IsNull(realScope.GetWriteLocks());
}
}
[Test]
public void ReadLocks_Not_Created_Until_First_Lock()
{
var scopeProvider = GetScopeProvider(out var syntaxProviderMock);
using (var scope = scopeProvider.CreateScope())
{
var realScope = (Scope)scope;
Assert.IsNull(realScope.GetReadLocks());
}
}
2021-03-02 10:53:10 +01:00
}
}