using System.IO; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Moq; using NUnit.Framework; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.Runtime; using Umbraco.Cms.Infrastructure.Runtime; using Umbraco.Cms.Tests.Integration.Testing; namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Runtime { [TestFixture] internal class FileSystemMainDomLockTests : UmbracoIntegrationTest { private IMainDomKeyGenerator MainDomKeyGenerator { get; set; } private IHostingEnvironment HostingEnvironment { get; set; } private FileSystemMainDomLock FileSystemMainDomLock { get; set; } private string LockFilePath { get; set; } private string LockReleaseFilePath { get; set; } [SetUp] public void SetUp() { MainDomKeyGenerator = GetRequiredService(); HostingEnvironment = GetRequiredService(); var lockFileName = $"MainDom_{MainDomKeyGenerator.GenerateKey()}.lock"; LockFilePath = Path.Combine(HostingEnvironment.LocalTempPath, lockFileName); LockReleaseFilePath = LockFilePath + "_release"; var globalSettings = Mock.Of>(); Mock.Get(globalSettings).Setup(x => x.CurrentValue).Returns(new GlobalSettings()); var log = GetRequiredService>(); FileSystemMainDomLock = new FileSystemMainDomLock(log, MainDomKeyGenerator, HostingEnvironment, globalSettings); } [TearDown] public void TearDown() { CleanupTestFile(LockFilePath); CleanupTestFile(LockReleaseFilePath); } private static void CleanupTestFile(string path) { for (var i = 0; i < 3; i++) { try { File.Delete(path); return; } catch { Thread.Sleep(500 * (i + 1)); } } } [Test] public async Task AcquireLockAsync_WhenNoOtherHoldsLockFileHandle_ReturnsTrue() { using var sut = FileSystemMainDomLock; var result = await sut.AcquireLockAsync(1000); Assert.True(result); } [Test] public async Task AcquireLockAsync_WhenTimeoutExceeded_ReturnsFalse() { await using var lockFile = File.Open(LockFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); using var sut = FileSystemMainDomLock; var result = await sut.AcquireLockAsync(1000); Assert.False(result); } [Test] public async Task ListenAsync_WhenLockReleaseSignalFileFound_DropsLockFileHandle() { using var sut = FileSystemMainDomLock; await sut.AcquireLockAsync(1000); var before = await sut.AcquireLockAsync(1000); sut.CreateLockReleaseSignalFile(); await sut.ListenAsync(); var after = await sut.AcquireLockAsync(1000); Assert.Multiple(() => { Assert.False(before); Assert.True(after); }); } } }