From 90d516cfb96bdc3197b440a5f2aaa632262b6042 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 11 Oct 2023 23:35:52 -0400 Subject: [PATCH] More OpenDream engine implementation --- .../Components/Engine/ByondInstallerBase.cs | 50 ++++++- .../Components/Engine/EngineInstallerBase.cs | 32 +--- .../Components/Engine/EngineManager.cs | 20 ++- .../Engine/IEngineInstallationData.cs | 20 +++ .../Components/Engine/IEngineInstaller.cs | 11 +- .../Components/Engine/OpenDreamInstaller.cs | 141 ++++++++++++++---- .../Components/Engine/PosixByondInstaller.cs | 2 +- .../RepositoryEngineInstallationData.cs | 59 ++++++++ .../Engine/WindowsByondInstaller.cs | 2 +- .../Engine/ZipStreamEngineInstallationData.cs | 43 ++++++ .../Configuration/GeneralConfiguration.cs | 10 ++ .../Engine/TestPosixByondInstaller.cs | 12 +- .../Live/Instance/ByondTest.cs | 2 +- .../Live/Instance/InstanceTest.cs | 2 +- tests/Tgstation.Server.Tests/TestVersions.cs | 44 +++--- tests/Tgstation.Server.Tests/TestingUtils.cs | 11 +- 16 files changed, 354 insertions(+), 107 deletions(-) create mode 100644 src/Tgstation.Server.Host/Components/Engine/IEngineInstallationData.cs create mode 100644 src/Tgstation.Server.Host/Components/Engine/RepositoryEngineInstallationData.cs create mode 100644 src/Tgstation.Server.Host/Components/Engine/ZipStreamEngineInstallationData.cs diff --git a/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs index f3659e3097..6f2b0854e6 100644 --- a/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs @@ -9,6 +9,7 @@ using Microsoft.Extensions.Logging; using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.IO; +using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Utils; namespace Tgstation.Server.Host.Components.Engine @@ -66,15 +67,21 @@ namespace Tgstation.Server.Host.Components.Engine /// protected abstract string ByondRevisionsUrlTemplate { get; } + /// + /// The for the . + /// + readonly IFileDownloader fileDownloader; + /// /// Initializes a new instance of the class. /// /// The for the . - /// The for the . /// The for the . - protected ByondInstallerBase(IIOManager ioManager, IFileDownloader fileDownloader, ILogger logger) - : base(ioManager, fileDownloader, logger) + /// The value of . + protected ByondInstallerBase(IIOManager ioManager, ILogger logger, IFileDownloader fileDownloader) + : base(ioManager, logger) { + this.fileDownloader = fileDownloader ?? throw new ArgumentNullException(nameof(fileDownloader)); } /// @@ -184,11 +191,29 @@ namespace Tgstation.Server.Host.Components.Engine } /// - protected override ValueTask GetDownloadZipUrl(ByondVersion version, CancellationToken cancellationToken) + public override async ValueTask DownloadVersion(ByondVersion version, JobProgressReporter progressReporter, CancellationToken cancellationToken) { CheckVersionValidity(version); - var url = String.Format(CultureInfo.InvariantCulture, ByondRevisionsUrlTemplate, version.Version.Major, version.Version.Minor); - return ValueTask.FromResult(new Uri(url)); + + var url = await GetDownloadZipUrl(version, cancellationToken); + Logger.LogTrace("Downloading {engineType} version {version} from {url}...", TargetEngineType, version, url); + + await using var download = fileDownloader.DownloadFile(url, null); + await using var buffer = new BufferedFileStreamProvider( + await download.GetResult(cancellationToken)); + + var stream = await buffer.GetOwnedResult(cancellationToken); + try + { + return new ZipStreamEngineInstallationData( + IOManager, + stream); + } + catch + { + await stream.DisposeAsync(); + throw; + } } /// @@ -198,5 +223,18 @@ namespace Tgstation.Server.Host.Components.Engine /// Whether or not the returned path supports being run as a command-line application. /// The file name of the DreamDaemon executable. protected abstract string GetDreamDaemonName(Version byondVersion, out bool supportsCli); + + /// + /// Create a pointing to the location of the download for a given . + /// + /// The to create a for. + /// The for the operation. + /// A resulting in a new pointing to the version download location. + ValueTask GetDownloadZipUrl(ByondVersion version, CancellationToken cancellationToken) + { + CheckVersionValidity(version); + var url = String.Format(CultureInfo.InvariantCulture, ByondRevisionsUrlTemplate, version.Version.Major, version.Version.Minor); + return ValueTask.FromResult(new Uri(url)); + } } } diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs b/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs index 94e0ffd1a9..002819ff6c 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs @@ -1,5 +1,4 @@ using System; -using System.IO; using System.Threading; using System.Threading.Tasks; @@ -8,6 +7,7 @@ using Microsoft.Extensions.Logging; using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.IO; +using Tgstation.Server.Host.Jobs; namespace Tgstation.Server.Host.Components.Engine { @@ -29,21 +29,14 @@ namespace Tgstation.Server.Host.Components.Engine /// protected ILogger Logger { get; } - /// - /// The for the . - /// - readonly IFileDownloader fileDownloader; - /// /// Initializes a new instance of the class. /// /// The value of . - /// The value of . /// The value of . - protected EngineInstallerBase(IIOManager ioManager, IFileDownloader fileDownloader, ILogger logger) + protected EngineInstallerBase(IIOManager ioManager, ILogger logger) { IOManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); - this.fileDownloader = fileDownloader ?? throw new ArgumentNullException(nameof(fileDownloader)); Logger = logger ?? throw new ArgumentNullException(nameof(logger)); } @@ -60,30 +53,11 @@ namespace Tgstation.Server.Host.Components.Engine public abstract ValueTask UpgradeInstallation(ByondVersion version, string path, CancellationToken cancellationToken); /// - public async ValueTask DownloadVersion(ByondVersion version, CancellationToken cancellationToken) - { - CheckVersionValidity(version); - - var url = await GetDownloadZipUrl(version, cancellationToken); - Logger.LogTrace("Downloading {engineType} version {version} from {url}...", TargetEngineType, version, url); - - await using var download = fileDownloader.DownloadFile(url, null); - await using var buffer = new BufferedFileStreamProvider( - await download.GetResult(cancellationToken)); - return await buffer.GetOwnedResult(cancellationToken); - } + public abstract ValueTask DownloadVersion(ByondVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken); /// public abstract ValueTask TrustDmbPath(string fullDmbPath, CancellationToken cancellationToken); - /// - /// Create a pointing to the location of the download for a given . - /// - /// The to create a for. - /// The for the operation. - /// A resulting in a new pointing to the version download location. - protected abstract ValueTask GetDownloadZipUrl(ByondVersion version, CancellationToken cancellationToken); - /// /// Check that a given is of type . /// diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs index b4594ef7b3..dc1bb72577 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs @@ -497,18 +497,24 @@ namespace Tgstation.Server.Host.Components.Engine var directoryCleanupTask = DirectoryCleanup(); try { - Stream versionZipStream; + IEngineInstallationData engineInstallationData; if (customVersionStream == null) { if (progressReporter != null) progressReporter.StageName = "Downloading version"; - versionZipStream = await engineInstaller.DownloadVersion(version, cancellationToken); + engineInstallationData = await engineInstaller.DownloadVersion(version, progressReporter, cancellationToken); + + progressReporter.ReportProgress(null); } else - versionZipStream = customVersionStream; +#pragma warning disable CA2000 // Dispose objects before losing scope, false positive + engineInstallationData = new ZipStreamEngineInstallationData( + ioManager, + customVersionStream); +#pragma warning restore CA2000 // Dispose objects before losing scope - await using (versionZipStream) + await using (engineInstallationData) { if (progressReporter != null) progressReporter.StageName = "Cleaning target directory"; @@ -516,10 +522,10 @@ namespace Tgstation.Server.Host.Components.Engine await directoryCleanupTask; if (progressReporter != null) - progressReporter.StageName = "Extracting zip"; + progressReporter.StageName = "Extracting data"; - logger.LogTrace("Extracting downloaded BYOND zip to {extractPath}...", installFullPath); - await ioManager.ZipToDirectory(installFullPath, versionZipStream, cancellationToken); + logger.LogTrace("Extracting engine to {extractPath}...", installFullPath); + await engineInstallationData.ExtractToPath(installFullPath, cancellationToken); } if (progressReporter != null) diff --git a/src/Tgstation.Server.Host/Components/Engine/IEngineInstallationData.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineInstallationData.cs new file mode 100644 index 0000000000..b3d8458973 --- /dev/null +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineInstallationData.cs @@ -0,0 +1,20 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Tgstation.Server.Host.Components.Engine +{ + /// + /// Wraps data containing an engine installation. + /// + interface IEngineInstallationData : IAsyncDisposable + { + /// + /// Extracts the installation to a given path. + /// + /// The full path to extract to. + /// The for the operation. + /// A representing the running operation. + Task ExtractToPath(string path, CancellationToken cancellationToken); + } +} diff --git a/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs index d4ba08d916..346599843e 100644 --- a/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs @@ -1,8 +1,8 @@ -using System.IO; -using System.Threading; +using System.Threading; using System.Threading.Tasks; using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Host.Jobs; namespace Tgstation.Server.Host.Components.Engine { @@ -22,10 +22,11 @@ namespace Tgstation.Server.Host.Components.Engine /// /// Download a given engine . /// - /// The of BYOND to download. + /// The of the engine to download. + /// The optional for the operation. /// The for the operation. - /// A resulting in a of the zipfile. - ValueTask DownloadVersion(ByondVersion version, CancellationToken cancellationToken); + /// A resulting in the for the download. + ValueTask DownloadVersion(ByondVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken); /// /// Does actions necessary to get an extracted installation working. diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index f12ba859d3..976131743c 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -4,14 +4,16 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Common; +using Tgstation.Server.Host.Components.Repository; +using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.System; -using Tgstation.Server.Host.Utils.GitHub; namespace Tgstation.Server.Host.Components.Engine { @@ -20,6 +22,11 @@ namespace Tgstation.Server.Host.Components.Engine /// sealed class OpenDreamInstaller : EngineInstallerBase { + /// + /// The name of the subdirectory used for the 's copy. + /// + private const string InstallationRepositorySubDirectory = "SourceRepo"; + /// protected override EngineType TargetEngineType => EngineType.OpenDream; @@ -28,37 +35,43 @@ namespace Tgstation.Server.Host.Components.Engine /// readonly IPlatformIdentifier platformIdentifier; - /// - /// The for the . - /// - readonly IGitHubService gitHubService; - /// /// The for the . /// readonly IProcessExecutor processExecutor; + /// + /// The for the OpenDream repository. + /// + readonly IRepositoryManager repositoryManager; + + /// + /// The for the . + /// + readonly GeneralConfiguration generalConfiguration; + /// /// Initializes a new instance of the class. /// /// The for the . - /// The for the . /// The for the . /// The value of . - /// The value of . /// The value of . + /// The value of . + /// The containing value of . public OpenDreamInstaller( IIOManager ioManager, - IFileDownloader fileDownloader, ILogger logger, IPlatformIdentifier platformIdentifier, - IGitHubService gitHubService, - IProcessExecutor processExecutor) - : base(ioManager, fileDownloader, logger) + IProcessExecutor processExecutor, + IRepositoryManager repositoryManager, + IOptions generalConfigurationOptions) + : base(ioManager, logger) { this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier)); - this.gitHubService = gitHubService ?? throw new ArgumentNullException(nameof(gitHubService)); this.processExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor)); + this.repositoryManager = repositoryManager ?? throw new ArgumentNullException(nameof(repositoryManager)); + generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); } /// @@ -72,10 +85,63 @@ namespace Tgstation.Server.Host.Components.Engine } /// - public override async ValueTask Install(ByondVersion version, string path, CancellationToken cancellationToken) + public override async ValueTask DownloadVersion(ByondVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken) { CheckVersionValidity(version); - ArgumentNullException.ThrowIfNull(path); + + // get a lock on a system wide OD repo + Logger.LogTrace("Cloning OD repo..."); + + var progressSection1 = jobProgressReporter.CreateSection("Updating OpenDream git repository", 0.5f); + + var repo = await repositoryManager.CloneRepository( + generalConfiguration.OpenDreamGitUrl, + null, + null, + null, + progressSection1, + true, + cancellationToken); + + try + { + if (repo == null) + { + Logger.LogTrace("OD repo seems to already exist, attempting load and fetch..."); + repo = await repositoryManager.LoadRepository(cancellationToken); + + await repo.FetchOrigin( + progressSection1, + null, + null, + false, + cancellationToken); + } + + var progressSection2 = jobProgressReporter.CreateSection("Checking out OpenDream version", 0.5f); + + await repo.CheckoutObject( + version.SourceCommittish, + null, + null, + true, + progressSection2, + cancellationToken); + + return new RepositoryEngineInstallationData(IOManager, repo, InstallationRepositorySubDirectory); + } + catch + { + repo?.Dispose(); + throw; + } + } + + /// + public override async ValueTask Install(ByondVersion version, string installPath, CancellationToken cancellationToken) + { + CheckVersionValidity(version); + ArgumentNullException.ThrowIfNull(installPath); var dotnetPaths = DotnetHelper.GetPotentialDotnetPaths(platformIdentifier.IsWindows) .ToList(); @@ -92,8 +158,33 @@ namespace Tgstation.Server.Host.Components.Engine var dotnetPath = dotnetPaths[selectedPathIndex]; - await Task.Yield(); - throw new NotImplementedException(); + var repositoryPath = IOManager.ConcatPath(installPath, InstallationRepositorySubDirectory); + + await using (var buildProcess = processExecutor.LaunchProcess( + dotnetPath, + repositoryPath, + "build -c Release", + null, + true, + true)) + { + var buildExitCode = await buildProcess.Lifetime; + if (buildExitCode != 0) + throw new JobException("OpenDream build failed!"); + } + + const string BinDirectory = "bin"; + await IOManager.MoveDirectory( + IOManager.ConcatPath( + repositoryPath, + BinDirectory, + "Content.Server"), + IOManager.ConcatPath( + installPath, + BinDirectory), + cancellationToken); + + await IOManager.DeleteDirectory(repositoryPath, cancellationToken); } /// @@ -110,21 +201,5 @@ namespace Tgstation.Server.Host.Components.Engine ArgumentNullException.ThrowIfNull(fullDmbPath); return ValueTask.CompletedTask; } - - /// - protected override async ValueTask GetDownloadZipUrl(ByondVersion version, CancellationToken cancellationToken) - { - throw new NotImplementedException("This won't work because of the goddamn fucking robust toolbox submodule"); - var fullCommit = await gitHubService.GetCommit("OpenDreamProject", "OpenDream", version.SourceCommittish, cancellationToken); - - if (fullCommit.Sha != version.SourceCommittish) - { - Logger.LogInformation("Replacing committish {committish} with full SHA {sha}...", version.SourceCommittish, fullCommit.Sha); - version.SourceCommittish = fullCommit.Sha; - } - - var gitHubDownloadUrlString = $"https://codeload.github.com/OpenDreamProject/OpenDream/zip/{version.SourceCommittish}"; - return new Uri(gitHubDownloadUrlString); - } } } diff --git a/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs index 06831bb98f..ed3785cfbd 100644 --- a/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs @@ -58,7 +58,7 @@ namespace Tgstation.Server.Host.Components.Engine IIOManager ioManager, IFileDownloader fileDownloader, ILogger logger) - : base(ioManager, fileDownloader, logger) + : base(ioManager, logger, fileDownloader) { this.postWriteHandler = postWriteHandler ?? throw new ArgumentNullException(nameof(postWriteHandler)); diff --git a/src/Tgstation.Server.Host/Components/Engine/RepositoryEngineInstallationData.cs b/src/Tgstation.Server.Host/Components/Engine/RepositoryEngineInstallationData.cs new file mode 100644 index 0000000000..88fbb77911 --- /dev/null +++ b/src/Tgstation.Server.Host/Components/Engine/RepositoryEngineInstallationData.cs @@ -0,0 +1,59 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +using Tgstation.Server.Host.Components.Repository; +using Tgstation.Server.Host.IO; + +namespace Tgstation.Server.Host.Components.Engine +{ + /// + /// Implementation of using a . + /// + sealed class RepositoryEngineInstallationData : IEngineInstallationData + { + /// + /// The for the . + /// + readonly IIOManager ioManager; + + /// + /// The backing . + /// + readonly IRepository repository; + + /// + /// The name of the subdirectory the is copied to. + /// + readonly string targetSubDirectory; + + /// + /// Initializes a new instance of the class. + /// + /// The value of . + /// The value of . + /// The value of . + public RepositoryEngineInstallationData(IIOManager ioManager, IRepository repository, string targetSubDirectory) + { + this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); + this.repository = repository ?? throw new ArgumentNullException(nameof(repository)); + this.targetSubDirectory = targetSubDirectory ?? throw new ArgumentNullException(nameof(targetSubDirectory)); + } + + /// + public ValueTask DisposeAsync() + { + repository.Dispose(); + return ValueTask.CompletedTask; + } + + /// + public Task ExtractToPath(string path, CancellationToken cancellationToken) + => repository.CopyTo( + ioManager.ConcatPath( + path, + targetSubDirectory), + cancellationToken) + .AsTask(); + } +} diff --git a/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs index 1d9336af8f..7795a69b6b 100644 --- a/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs @@ -96,7 +96,7 @@ namespace Tgstation.Server.Host.Components.Engine IFileDownloader fileDownloader, IOptions generalConfigurationOptions, ILogger logger) - : base(ioManager, fileDownloader, logger) + : base(ioManager, logger, fileDownloader) { this.processExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor)); generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); diff --git a/src/Tgstation.Server.Host/Components/Engine/ZipStreamEngineInstallationData.cs b/src/Tgstation.Server.Host/Components/Engine/ZipStreamEngineInstallationData.cs new file mode 100644 index 0000000000..292b725981 --- /dev/null +++ b/src/Tgstation.Server.Host/Components/Engine/ZipStreamEngineInstallationData.cs @@ -0,0 +1,43 @@ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +using Tgstation.Server.Host.IO; + +namespace Tgstation.Server.Host.Components.Engine +{ + /// + /// Implementation of for a zip file in a . + /// + sealed class ZipStreamEngineInstallationData : IEngineInstallationData + { + /// + /// The for the . + /// + readonly IIOManager ioManager; + + /// + /// The containing the zip data of the engine. + /// + readonly Stream zipStream; + + /// + /// Initializes a new instance of the class. + /// + /// The value of . + /// The value of . + public ZipStreamEngineInstallationData(IIOManager ioManager, Stream zipStream) + { + this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); + this.zipStream = zipStream ?? throw new ArgumentNullException(nameof(zipStream)); + } + + /// + public ValueTask DisposeAsync() => zipStream.DisposeAsync(); + + /// + public Task ExtractToPath(string path, CancellationToken cancellationToken) + => ioManager.ZipToDirectory(path, zipStream, cancellationToken); + } +} diff --git a/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs b/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs index 7b02f6d177..668e158241 100644 --- a/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs @@ -61,6 +61,11 @@ namespace Tgstation.Server.Host.Configuration /// const uint DefaultShutdownTimeoutMinutes = 300; + /// + /// The default value for . + /// + const string DefaultOpenDreamGitUrl = "https://github.com/OpenDreamProject/OpenDream"; + /// /// The current . /// @@ -122,6 +127,11 @@ namespace Tgstation.Server.Host.Configuration /// public uint? DeploymentDirectoryCopyTasksPerCore { get; set; } + /// + /// Location of a publically accessible OpenDream repository. + /// + public Uri OpenDreamGitUrl { get; set; } = new Uri(DefaultOpenDreamGitUrl); + /// /// Initializes a new instance of the class. /// diff --git a/tests/Tgstation.Server.Host.Tests/Components/Engine/TestPosixByondInstaller.cs b/tests/Tgstation.Server.Host.Tests/Components/Engine/TestPosixByondInstaller.cs index e17ac8a490..4e57ddc2de 100644 --- a/tests/Tgstation.Server.Host.Tests/Components/Engine/TestPosixByondInstaller.cs +++ b/tests/Tgstation.Server.Host.Tests/Components/Engine/TestPosixByondInstaller.cs @@ -4,6 +4,7 @@ using Moq; using System; using System.IO; using System.Linq; +using System.Reflection; using System.Threading.Tasks; using Tgstation.Server.Api.Models; @@ -51,7 +52,7 @@ namespace Tgstation.Server.Host.Components.Engine.Tests var mockFileDownloader = new Mock(); var installer = new PosixByondInstaller(mockPostWriteHandler.Object, mockIOManager.Object, mockFileDownloader.Object, mockLogger.Object); - await Assert.ThrowsExceptionAsync(() => installer.DownloadVersion(null, default).AsTask()); + await Assert.ThrowsExceptionAsync(() => installer.DownloadVersion(null, null, default).AsTask()); var ourArray = Array.Empty(); mockFileDownloader @@ -64,15 +65,20 @@ namespace Tgstation.Server.Host.Components.Engine.Tests new MemoryStream(ourArray))) .Verifiable(); - var result = await installer.DownloadVersion(new ByondVersion + var result = ExtractMemoryStreamFromInstallationData(await installer.DownloadVersion(new ByondVersion { Engine = EngineType.Byond, Version = new Version(123, 252345), - }, default); + }, null, default)); Assert.IsTrue(ourArray.SequenceEqual(result.ToArray())); mockIOManager.Verify(); } + static MemoryStream ExtractMemoryStreamFromInstallationData(IEngineInstallationData engineInstallationData) + { + var zipStreamData = (ZipStreamEngineInstallationData)engineInstallationData; + return (MemoryStream)zipStreamData.GetType().GetField("stream", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(zipStreamData); + } [TestMethod] public async Task TestInstallByond() diff --git a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs index 16e059e70e..0aa49b4a53 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs @@ -254,7 +254,7 @@ namespace Tgstation.Server.Tests.Live.Instance using var windowsByondInstaller = byondInstaller as WindowsByondInstaller; // get the bytes for stable - using var stableBytesMs = await byondInstaller.DownloadVersion(testVersion, cancellationToken); + using var stableBytesMs = TestingUtils.ExtractMemoryStreamFromInstallationData(await byondInstaller.DownloadVersion(testVersion, null, cancellationToken)); var test = await byondClient.SetActiveVersion( new ByondVersionRequest diff --git a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs index 0ab2cb1acf..7dd1e99253 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs @@ -158,7 +158,7 @@ namespace Tgstation.Server.Tests.Live.Instance // get the bytes for stable ByondInstallResponse installJob2; - using (var stableBytesMs = await byondInstaller.DownloadVersion(compatVersion, cancellationToken)) + using (var stableBytesMs = TestingUtils.ExtractMemoryStreamFromInstallationData(await byondInstaller.DownloadVersion(compatVersion, null, cancellationToken))) { installJob2 = await instanceClient.Byond.SetActiveVersion(new ByondVersionRequest { diff --git a/tests/Tgstation.Server.Tests/TestVersions.cs b/tests/Tgstation.Server.Tests/TestVersions.cs index 06cce64ee7..eac841d7bc 100644 --- a/tests/Tgstation.Server.Tests/TestVersions.cs +++ b/tests/Tgstation.Server.Tests/TestVersions.cs @@ -127,13 +127,15 @@ namespace Tgstation.Server.Tests const string ArchiveEntryPath = "byond/bin/dd.exe"; var hasEntry = ArchiveHasFileEntry( - await byondInstaller.DownloadVersion( - new ByondVersion - { - Engine = EngineType.Byond, - Version = WindowsByondInstaller.DDExeVersion - }, - default), + TestingUtils.ExtractMemoryStreamFromInstallationData( + await byondInstaller.DownloadVersion( + new ByondVersion + { + Engine = EngineType.Byond, + Version = WindowsByondInstaller.DDExeVersion + }, + null, + default)), ArchiveEntryPath); Assert.IsTrue(hasEntry); @@ -218,13 +220,15 @@ namespace Tgstation.Server.Tests Engine = EngineType.Byond, Version = MapThreadsVersion(), }, - await byondInstaller.DownloadVersion( - new ByondVersion - { - Engine = EngineType.Byond, - Version = MapThreadsVersion() - }, - default), + TestingUtils.ExtractMemoryStreamFromInstallationData( + await byondInstaller.DownloadVersion( + new ByondVersion + { + Engine = EngineType.Byond, + Version = MapThreadsVersion() + }, + null, + default)), byondInstaller, ioManager, processExecutor, @@ -400,7 +404,7 @@ namespace Tgstation.Server.Tests Assert.AreEqual(latestMigrationSL, DatabaseContext.SLLatestMigration); } - static async Task> GetByondVersionPriorTo(IEngineInstaller byondInstaller, Version version) + static async Task> GetByondVersionPriorTo(ByondInstallerBase byondInstaller, Version version) { var minusOneMinor = new Version(version.Major, version.Minor - 1); var byondVersion = new ByondVersion @@ -410,17 +414,19 @@ namespace Tgstation.Server.Tests }; try { - return Tuple.Create(await byondInstaller.DownloadVersion( + return Tuple.Create(TestingUtils.ExtractMemoryStreamFromInstallationData(await byondInstaller.DownloadVersion( byondVersion, - CancellationToken.None), byondVersion); + null, + CancellationToken.None)), byondVersion); } catch (HttpRequestException) { var minusOneMajor = new Version(minusOneMinor.Major - 1, minusOneMinor.Minor); byondVersion.Version = minusOneMajor; - return Tuple.Create(await byondInstaller.DownloadVersion( + return Tuple.Create(TestingUtils.ExtractMemoryStreamFromInstallationData(await byondInstaller.DownloadVersion( byondVersion, - CancellationToken.None), byondVersion); + null, + CancellationToken.None)), byondVersion); } } diff --git a/tests/Tgstation.Server.Tests/TestingUtils.cs b/tests/Tgstation.Server.Tests/TestingUtils.cs index d4f8d8caa3..cef9f817cf 100644 --- a/tests/Tgstation.Server.Tests/TestingUtils.cs +++ b/tests/Tgstation.Server.Tests/TestingUtils.cs @@ -1,10 +1,13 @@ using System; +using System.IO; +using System.Reflection; using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; +using Tgstation.Server.Host.Components.Engine; + namespace Tgstation.Server.Tests { static class TestingUtils @@ -25,5 +28,11 @@ namespace Tgstation.Server.Tests .Verifiable(); return mockLoggerFactory.Object; } + + public static MemoryStream ExtractMemoryStreamFromInstallationData(IEngineInstallationData engineInstallationData) + { + var zipStreamData = (ZipStreamEngineInstallationData)engineInstallationData; + return (MemoryStream)zipStreamData.GetType().GetField("stream", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(zipStreamData); + } } }