diff --git a/src/ByteSync.Client/Business/Inventories/FileSystemEntryKind.cs b/src/ByteSync.Client/Business/Inventories/FileSystemEntryKind.cs new file mode 100644 index 00000000..43fe8f84 --- /dev/null +++ b/src/ByteSync.Client/Business/Inventories/FileSystemEntryKind.cs @@ -0,0 +1,13 @@ +namespace ByteSync.Business.Inventories; + +public enum FileSystemEntryKind +{ + Unknown = 0, + RegularFile = 1, + Directory = 2, + BlockDevice = 3, + CharacterDevice = 4, + Fifo = 5, + Socket = 6, + Symlink = 7 +} diff --git a/src/ByteSync.Client/ByteSync.Client.csproj b/src/ByteSync.Client/ByteSync.Client.csproj index 232fbee3..436be7c5 100644 --- a/src/ByteSync.Client/ByteSync.Client.csproj +++ b/src/ByteSync.Client/ByteSync.Client.csproj @@ -1,260 +1,261 @@ - - WinExe - enable - true - Assets\ByteSync.ico - net8.0 - win-x64;linux-x64 - true - true - true - default - ByteSync.Client - ByteSync - ByteSync - false - false - true - true - + + WinExe + enable + true + Assets\ByteSync.ico + net8.0 + win-x64;linux-x64 + true + true + true + default + ByteSync.Client + ByteSync + ByteSync + false + false + true + true + - - WIN - + + WIN + - - OSX - + + OSX + - - LIN - - - - - - - - - - - - - - - - - - - Never - - - - - - - - - - - - - - - - - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - - - - - - - - - - - - - - - - - - Resources.resx - - - ResXFileCodeGenerator - Resources.Designer.cs - - - - - - - - - - - True - True - Resources.resx - - - - - Designer - - - - - Resources.resx - - - - - ActivityIndicator.axaml - - - CurrentCloudSessionView.axaml - Code - - - JoinCloudSessionView.axaml - Code - - - StartCloudSessionView.axaml - Code - - - StartOrJoinView.axaml - Code - - - ComparisonResultView.axaml - Code - - - StatusView.axaml - Code - - - SynchronizationActionView.axaml - Code - - - ManageSynchronizationRulesView.axaml - Code - - - ContentIdentityView.axaml - Code - - - AutomaticActionSummaryView.axaml - Code - - - AtomicActionEditView.axaml - Code - - - AtomicConditionEditView.axaml - Code - - - SynchronizationRulesGlobalView.axaml - Code - - - ManualActionEditionGlobalView.axaml - Code - - - SessionSettingsEditView.axaml - Code - - - HomeMainView.axaml - Code - - - SelectLocaleView.axaml - Code - - - AddTrustedClientView.axaml - Code - - - TrustedPublicKeysView.axaml - Code - - - ProfilesView.axaml - Code - - - AccountDetailsView.axaml - Code - - - UsageStatisticsView.axaml - Code - - - SessionSettingsEditView.axaml - Code - - - AnnouncementView.axaml - Code - - - DataNodeHeaderView.axaml - Code - - - DataNodeSourcesView.axaml - Code - - - DataNodeStatusView.axaml - Code - - - DataNodeView.axaml - Code - - - AddTrustedClientView.axaml - Code - - - AnnouncementView.axaml - Code - - + + LIN + + + + + + + + + + + + + + + + + + + Never + + + + + + + + + + + + + + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + + + + + + + + + + + + Resources.resx + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + + + + + + True + True + Resources.resx + + + + + Designer + + + + + Resources.resx + + + + + ActivityIndicator.axaml + + + CurrentCloudSessionView.axaml + Code + + + JoinCloudSessionView.axaml + Code + + + StartCloudSessionView.axaml + Code + + + StartOrJoinView.axaml + Code + + + ComparisonResultView.axaml + Code + + + StatusView.axaml + Code + + + SynchronizationActionView.axaml + Code + + + ManageSynchronizationRulesView.axaml + Code + + + ContentIdentityView.axaml + Code + + + AutomaticActionSummaryView.axaml + Code + + + AtomicActionEditView.axaml + Code + + + AtomicConditionEditView.axaml + Code + + + SynchronizationRulesGlobalView.axaml + Code + + + ManualActionEditionGlobalView.axaml + Code + + + SessionSettingsEditView.axaml + Code + + + HomeMainView.axaml + Code + + + SelectLocaleView.axaml + Code + + + AddTrustedClientView.axaml + Code + + + TrustedPublicKeysView.axaml + Code + + + ProfilesView.axaml + Code + + + AccountDetailsView.axaml + Code + + + UsageStatisticsView.axaml + Code + + + SessionSettingsEditView.axaml + Code + + + AnnouncementView.axaml + Code + + + DataNodeHeaderView.axaml + Code + + + DataNodeSourcesView.axaml + Code + + + DataNodeStatusView.axaml + Code + + + DataNodeView.axaml + Code + + + AddTrustedClientView.axaml + Code + + + AnnouncementView.axaml + Code + + diff --git a/src/ByteSync.Client/Interfaces/Controls/Inventories/IPosixFileTypeClassifier.cs b/src/ByteSync.Client/Interfaces/Controls/Inventories/IPosixFileTypeClassifier.cs new file mode 100644 index 00000000..a46b2f6b --- /dev/null +++ b/src/ByteSync.Client/Interfaces/Controls/Inventories/IPosixFileTypeClassifier.cs @@ -0,0 +1,8 @@ +using ByteSync.Business.Inventories; + +namespace ByteSync.Interfaces.Controls.Inventories; + +public interface IPosixFileTypeClassifier +{ + FileSystemEntryKind ClassifyPosixEntry(string path); +} diff --git a/src/ByteSync.Client/Services/Inventories/InventoryBuilder.cs b/src/ByteSync.Client/Services/Inventories/InventoryBuilder.cs index 0afc7987..968c0e5c 100644 --- a/src/ByteSync.Client/Services/Inventories/InventoryBuilder.cs +++ b/src/ByteSync.Client/Services/Inventories/InventoryBuilder.cs @@ -26,7 +26,8 @@ public InventoryBuilder(SessionMember sessionMember, DataNode dataNode, SessionS IInventoryFileAnalyzer inventoryFileAnalyzer, IInventorySaver inventorySaver, IInventoryIndexer inventoryIndexer, - IFileSystemInspector? fileSystemInspector = null) + IFileSystemInspector? fileSystemInspector = null, + IPosixFileTypeClassifier? posixFileTypeClassifier = null) { _logger = logger; @@ -45,6 +46,7 @@ public InventoryBuilder(SessionMember sessionMember, DataNode dataNode, SessionS InventoryFileAnalyzer = inventoryFileAnalyzer; FileSystemInspector = fileSystemInspector ?? new FileSystemInspector(); + PosixFileTypeClassifier = posixFileTypeClassifier ?? new PosixFileTypeClassifier(); } private Inventory InstantiateInventory() @@ -87,6 +89,8 @@ private Inventory InstantiateInventory() private IFileSystemInspector FileSystemInspector { get; } + private IPosixFileTypeClassifier PosixFileTypeClassifier { get; } + private bool IgnoreHidden { get { return SessionSettings is { ExcludeHiddenFiles: true }; } @@ -305,7 +309,7 @@ private void AddInaccessibleDirectoryAndLog(InventoryPart inventoryPart, Directo AddFileSystemDescription(inventoryPart, subDirectoryDescription); _logger.LogWarning(ex, message, directoryInfo.FullName); } - + private bool IsRootPath(InventoryPart inventoryPart, FileSystemInfo fileSystemInfo) { var rootPath = NormalizePath(inventoryPart.RootPath); @@ -359,6 +363,14 @@ private bool ShouldIgnoreHiddenDirectory(DirectoryInfo directoryInfo) { var isRoot = IsRootPath(inventoryPart, fileInfo); + var entryKind = PosixFileTypeClassifier.ClassifyPosixEntry(fileInfo.FullName); + if (IsPosixSpecialFile(entryKind)) + { + AddPosixSpecialFileAndLog(inventoryPart, fileInfo, entryKind); + + return; + } + if (!isRoot && ShouldIgnoreHiddenFile(fileInfo)) { return; @@ -527,6 +539,27 @@ private void AddInaccessibleFileAndLog(InventoryPart inventoryPart, FileInfo fil _logger.LogWarning(ex, message, fileInfo.FullName); } + private void AddPosixSpecialFileAndLog(InventoryPart inventoryPart, FileInfo fileInfo, FileSystemEntryKind entryKind) + { + inventoryPart.IsIncompleteDueToAccess = true; + var relativePath = BuildRelativePath(inventoryPart, fileInfo); + var fileDescription = new FileDescription(inventoryPart, relativePath) + { + IsAccessible = false + }; + AddFileSystemDescription(inventoryPart, fileDescription); + _logger.LogWarning("File {File} is a POSIX special file ({EntryKind}) and will be skipped", fileInfo.FullName, entryKind); + } + + private static bool IsPosixSpecialFile(FileSystemEntryKind entryKind) + { + return entryKind is + FileSystemEntryKind.BlockDevice or + FileSystemEntryKind.CharacterDevice or + FileSystemEntryKind.Fifo or + FileSystemEntryKind.Socket; + } + private string BuildRelativePath(InventoryPart inventoryPart, FileInfo fileInfo) { if (inventoryPart.InventoryPartType != FileSystemTypes.Directory) @@ -584,4 +617,4 @@ private void AddFileSystemDescription(InventoryPart inventoryPart, FileSystemDes } } } -} +} \ No newline at end of file diff --git a/src/ByteSync.Client/Services/Inventories/PosixFileTypeClassifier.cs b/src/ByteSync.Client/Services/Inventories/PosixFileTypeClassifier.cs new file mode 100644 index 00000000..1b612c44 --- /dev/null +++ b/src/ByteSync.Client/Services/Inventories/PosixFileTypeClassifier.cs @@ -0,0 +1,150 @@ +using ByteSync.Business.Inventories; +using ByteSync.Interfaces.Controls.Inventories; +using Mono.Unix; +using Mono.Unix.Native; + +namespace ByteSync.Services.Inventories; + +public class PosixFileTypeClassifier : IPosixFileTypeClassifier +{ + private readonly Func _unixFileInfoFactory; + private readonly Func _tryGetMode; + + public PosixFileTypeClassifier() + : this(path => new UnixFileInfo(path), TryGetModeDefault) + { + } + + public PosixFileTypeClassifier(Func unixFileInfoFactory) + : this(unixFileInfoFactory, TryGetModeDefault) + { + } + + public PosixFileTypeClassifier(Func unixFileInfoFactory, + Func tryGetMode) + { + _unixFileInfoFactory = unixFileInfoFactory; + _tryGetMode = tryGetMode; + } + + public FileSystemEntryKind ClassifyPosixEntry(string path) + { + if (OperatingSystem.IsWindows()) + { + return FileSystemEntryKind.Unknown; + } + + try + { + var modeResult = _tryGetMode(path); + if (!modeResult.Success) + { + return FileSystemEntryKind.Unknown; + } + + var entryKind = MapFilePermissions(modeResult.Type); + if (entryKind == FileSystemEntryKind.RegularFile || entryKind == FileSystemEntryKind.Unknown) + { + var unixKind = TryClassifyWithUnixFileInfo(path); + if (unixKind != FileSystemEntryKind.Unknown) + { + return unixKind; + } + } + + return entryKind; + } + catch (DllNotFoundException) + { + return FileSystemEntryKind.Unknown; + } + catch (EntryPointNotFoundException) + { + return FileSystemEntryKind.Unknown; + } + catch (PlatformNotSupportedException) + { + return FileSystemEntryKind.Unknown; + } + } + + private static (bool Success, FilePermissions Type) TryGetModeDefault(string path) + { + if (Syscall.lstat(path, out var stat) != 0) + { + if (Syscall.stat(path, out stat) != 0) + { + return (false, 0); + } + } + + var mode = stat.st_mode; + var type = mode & FilePermissions.S_IFMT; + + return (true, type); + } + + private static FileSystemEntryKind MapFilePermissions(FilePermissions type) + { + if (type == FilePermissions.S_IFREG) + { + return FileSystemEntryKind.RegularFile; + } + + if (type == FilePermissions.S_IFDIR) + { + return FileSystemEntryKind.Directory; + } + + if (type == FilePermissions.S_IFBLK) + { + return FileSystemEntryKind.BlockDevice; + } + + if (type == FilePermissions.S_IFCHR) + { + return FileSystemEntryKind.CharacterDevice; + } + + if (type == FilePermissions.S_IFIFO) + { + return FileSystemEntryKind.Fifo; + } + + if (type == FilePermissions.S_IFSOCK) + { + return FileSystemEntryKind.Socket; + } + + if (type == FilePermissions.S_IFLNK) + { + return FileSystemEntryKind.Symlink; + } + + return FileSystemEntryKind.Unknown; + } + + private FileSystemEntryKind TryClassifyWithUnixFileInfo(string path) + { + try + { + var info = _unixFileInfoFactory(path); + + return info.FileType switch + { + FileTypes.BlockDevice => FileSystemEntryKind.BlockDevice, + FileTypes.CharacterDevice => FileSystemEntryKind.CharacterDevice, + FileTypes.Fifo => FileSystemEntryKind.Fifo, + FileTypes.Socket => FileSystemEntryKind.Socket, + FileTypes.Directory => FileSystemEntryKind.Directory, + FileTypes.RegularFile => FileSystemEntryKind.RegularFile, + FileTypes.SymbolicLink => FileSystemEntryKind.Symlink, + _ => FileSystemEntryKind.Unknown + }; + } + catch (Exception) + { + return FileSystemEntryKind.Unknown; + } + } +} diff --git a/tests/ByteSync.Client.IntegrationTests/Services/Inventories/TestInventoryBuilder.cs b/tests/ByteSync.Client.IntegrationTests/Services/Inventories/TestInventoryBuilder.cs index 9f729e5a..854fafbb 100644 --- a/tests/ByteSync.Client.IntegrationTests/Services/Inventories/TestInventoryBuilder.cs +++ b/tests/ByteSync.Client.IntegrationTests/Services/Inventories/TestInventoryBuilder.cs @@ -1,3 +1,4 @@ +using System.Diagnostics; using Autofac; using ByteSync.Business; using ByteSync.Business.DataNodes; @@ -716,6 +717,60 @@ public async Task Test_ReparsePoint() inventory.InventoryParts[0].DirectoryDescriptions.Count.Should().Be(1); inventory.InventoryParts[0].FileDescriptions.Count.Should().Be(2); } + + [Test] + [Platform(Include = "Linux,MacOsX")] + public async Task Test_PosixFifo_IsSkipped() + { + InventoryBuilder inventoryBuilder; + Inventory inventory; + + DirectoryInfo sourceA, unzipDir; + FileInfo fileInfo; + + sourceA = new DirectoryInfo(IOUtils.Combine(_testDirectoryService.TestDirectory.FullName, "sourceA")); + sourceA.Create(); + fileInfo = new FileInfo(_testDirectoryService.CreateFileInDirectory(sourceA.FullName, "fileA.txt", "fileAContent").FullName); + + var fifoPath = IOUtils.Combine(sourceA.FullName, "pipeA"); + CreateFifo(fifoPath); + + var classifier = new PosixFileTypeClassifier(); + var fifoKind = classifier.ClassifyPosixEntry(fifoPath); + if (fifoKind == FileSystemEntryKind.Unknown) + { + Assert.Ignore($"POSIX classification returned Unknown for '{fifoPath}'."); + } + + var inventoryAFilePath = IOUtils.Combine(_testDirectoryService.TestDirectory.FullName, $"inventoryA.zip"); + + var sessionSettings = SessionSettings.BuildDefault(); + var osPlatform = OperatingSystem.IsMacOS() ? OSPlatforms.MacOs : OSPlatforms.Linux; + + inventoryBuilder = BuildInventoryBuilder(sessionSettings, null, null, osPlatform); + inventoryBuilder.AddInventoryPart(sourceA.FullName); + await inventoryBuilder.BuildBaseInventoryAsync(inventoryAFilePath); + + File.Exists(inventoryAFilePath).Should().BeTrue(); + + unzipDir = new DirectoryInfo(IOUtils.Combine(_testDirectoryService.TestDirectory.FullName, "unzip")); + unzipDir.Create(); + + var fastZip = new FastZip(); + fastZip.ExtractZip(inventoryAFilePath, unzipDir.FullName, null); + + unzipDir.GetFiles("*", SearchOption.AllDirectories).Length.Should().Be(1); + File.Exists(IOUtils.Combine(unzipDir.FullName, $"inventory.json")).Should().BeTrue(); + + inventory = inventoryBuilder.Inventory!; + inventory.InventoryParts.Count.Should().Be(1); + inventory.InventoryParts[0].DirectoryDescriptions.Count.Should().Be(0); + inventory.InventoryParts[0].FileDescriptions.Count.Should().Be(2); + + var fifoDescription = inventory.InventoryParts[0].FileDescriptions.Single(fd => fd.Name.Equals("pipeA")); + fifoDescription.IsAccessible.Should().BeFalse(); + inventory.InventoryParts[0].IsIncompleteDueToAccess.Should().BeTrue(); + } [Test] public async Task Test_GetBuildingStageData() @@ -873,4 +928,21 @@ private InventoryBuilder BuildInventoryBuilder(SessionSettings? sessionSettings saver, new InventoryIndexer()); } + + private static void CreateFifo(string path) + { + var startInfo = new ProcessStartInfo("mkfifo", path) + { + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false + }; + + using var process = Process.Start(startInfo); + process.Should().NotBeNull(); + process!.WaitForExit(); + + var error = process.StandardError.ReadToEnd(); + process.ExitCode.Should().Be(0, error); + } } diff --git a/tests/ByteSync.Client.UnitTests/Services/Inventories/PosixFileTypeClassifierTests.cs b/tests/ByteSync.Client.UnitTests/Services/Inventories/PosixFileTypeClassifierTests.cs new file mode 100644 index 00000000..f29975ba --- /dev/null +++ b/tests/ByteSync.Client.UnitTests/Services/Inventories/PosixFileTypeClassifierTests.cs @@ -0,0 +1,197 @@ +using System.IO; +using ByteSync.Business.Inventories; +using ByteSync.Services.Inventories; +using FluentAssertions; +using NUnit.Framework; + +namespace ByteSync.Client.UnitTests.Services.Inventories; + +public class PosixFileTypeClassifierTests +{ + [Test] + [Platform(Include = "Linux,MacOsX")] + [TestCase("/dev/null", FileSystemEntryKind.CharacterDevice)] + [TestCase("/dev/zero", FileSystemEntryKind.CharacterDevice)] + public void ClassifyPosixEntry_ReturnsExpected(string path, FileSystemEntryKind expected) + { + if (!File.Exists(path)) + { + Assert.Ignore($"Path '{path}' not found on this system."); + } + + var classifier = new PosixFileTypeClassifier(); + + var result = classifier.ClassifyPosixEntry(path); + + if (result == FileSystemEntryKind.Unknown) + { + Assert.Ignore($"POSIX classification returned Unknown for '{path}'."); + } + + result.Should().Be(expected); + } + + [Test] + [Platform(Include = "Linux,MacOsX")] + public void ClassifyPosixEntry_ReturnsRegularFile_ForTempFile() + { + var classifier = new PosixFileTypeClassifier(); + var tempDirectory = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")); + Directory.CreateDirectory(tempDirectory); + var tempFile = Path.Combine(tempDirectory, "file.txt"); + File.WriteAllText(tempFile, "data"); + + try + { + var result = classifier.ClassifyPosixEntry(tempFile); + + if (result == FileSystemEntryKind.Unknown) + { + Assert.Ignore($"POSIX classification returned Unknown for '{tempFile}'."); + } + + result.Should().Be(FileSystemEntryKind.RegularFile); + } + finally + { + Directory.Delete(tempDirectory, true); + } + } + + [Test] + [Platform(Include = "Linux,MacOsX")] + public void ClassifyPosixEntry_ReturnsDirectory_ForTempDirectory() + { + var classifier = new PosixFileTypeClassifier(); + var tempDirectory = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")); + Directory.CreateDirectory(tempDirectory); + + try + { + var result = classifier.ClassifyPosixEntry(tempDirectory); + + if (result == FileSystemEntryKind.Unknown) + { + Assert.Ignore($"POSIX classification returned Unknown for '{tempDirectory}'."); + } + + result.Should().Be(FileSystemEntryKind.Directory); + } + finally + { + Directory.Delete(tempDirectory, true); + } + } + + [Test] + [Platform(Include = "Linux,MacOsX")] + public void ClassifyPosixEntry_ReturnsUnknown_ForMissingPath() + { + var classifier = new PosixFileTypeClassifier(); + var missingPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"), "missing"); + + var result = classifier.ClassifyPosixEntry(missingPath); + + result.Should().Be(FileSystemEntryKind.Unknown); + } + + [Test] + [Platform(Include = "Linux,MacOsX")] + public void ClassifyPosixEntry_ReturnsSymlink_WhenSupported() + { + var classifier = new PosixFileTypeClassifier(); + var tempDirectory = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")); + Directory.CreateDirectory(tempDirectory); + var targetFile = Path.Combine(tempDirectory, "target.txt"); + File.WriteAllText(targetFile, "data"); + var linkPath = Path.Combine(tempDirectory, "link.txt"); + + try + { + try + { + File.CreateSymbolicLink(linkPath, targetFile); + } + catch (Exception ex) + { + Assert.Ignore($"Symbolic link creation failed: {ex.GetType().Name}"); + } + + var result = classifier.ClassifyPosixEntry(linkPath); + + if (result == FileSystemEntryKind.Unknown) + { + Assert.Ignore($"POSIX classification returned Unknown for '{linkPath}'."); + } + + result.Should().Be(FileSystemEntryKind.Symlink); + } + finally + { + Directory.Delete(tempDirectory, true); + } + } + + [Test] + [Platform(Include = "Linux,MacOsX")] + public void ClassifyPosixEntry_ReturnsUnknown_WhenUnixFileInfoThrows() + { + var classifier = new PosixFileTypeClassifier(_ => throw new InvalidOperationException("fail")); + var tempDirectory = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")); + Directory.CreateDirectory(tempDirectory); + var tempFile = Path.Combine(tempDirectory, "file.txt"); + File.WriteAllText(tempFile, "data"); + + try + { + var result = classifier.ClassifyPosixEntry(tempFile); + + if (result == FileSystemEntryKind.Unknown) + { + Assert.Ignore($"POSIX classification returned Unknown for '{tempFile}'."); + } + + result.Should().Be(FileSystemEntryKind.RegularFile); + } + finally + { + Directory.Delete(tempDirectory, true); + } + } + + [Test] + [Platform(Include = "Linux,MacOsX")] + public void ClassifyPosixEntry_ReturnsUnknown_WhenDllNotFound() + { + var classifier = new PosixFileTypeClassifier(_ => throw new InvalidOperationException("unused"), + _ => throw new DllNotFoundException("missing")); + + var result = classifier.ClassifyPosixEntry("/tmp"); + + result.Should().Be(FileSystemEntryKind.Unknown); + } + + [Test] + [Platform(Include = "Linux,MacOsX")] + public void ClassifyPosixEntry_ReturnsUnknown_WhenEntryPointNotFound() + { + var classifier = new PosixFileTypeClassifier(_ => throw new InvalidOperationException("unused"), + _ => throw new EntryPointNotFoundException("missing")); + + var result = classifier.ClassifyPosixEntry("/tmp"); + + result.Should().Be(FileSystemEntryKind.Unknown); + } + + [Test] + [Platform(Include = "Linux,MacOsX")] + public void ClassifyPosixEntry_ReturnsUnknown_WhenPlatformNotSupported() + { + var classifier = new PosixFileTypeClassifier(_ => throw new InvalidOperationException("unused"), + _ => throw new PlatformNotSupportedException("missing")); + + var result = classifier.ClassifyPosixEntry("/tmp"); + + result.Should().Be(FileSystemEntryKind.Unknown); + } +} diff --git a/tests/ByteSync.Functions.IntegrationTests/End2End/E2E_Environment_Setup.cs b/tests/ByteSync.Functions.IntegrationTests/End2End/E2E_Environment_Setup.cs index 757edb2d..6b8873f6 100644 --- a/tests/ByteSync.Functions.IntegrationTests/End2End/E2E_Environment_Setup.cs +++ b/tests/ByteSync.Functions.IntegrationTests/End2End/E2E_Environment_Setup.cs @@ -70,6 +70,11 @@ string ResolveFunctionsProjectRoot() var env = new Dictionary { ["AzureWebJobsStorage"] = cfg["AzureWebJobsStorage"]!, + ["FUNCTIONS_WORKER_RUNTIME"] = "dotnet-isolated", + ["AzureWebJobsScriptRoot"] = "/home/site/wwwroot", + ["AZURE_FUNCTIONS_ENVIRONMENT"] = "Development", + ["AzureFunctionsJobHost__Logging__LogLevel__Default"] = "Information", + ["AzureFunctionsJobHost__Logging__LogLevel__Host"] = "Information", ["AppSettings__SkipClientsVersionCheck"] = "True", ["Redis__ConnectionString"] = cfg["Redis:ConnectionString"]!, ["SignalR__ConnectionString"] = cfg["SignalR:ConnectionString"]!,