From 6b08ff0a21767b353aaaf349859d4940e479dd6e Mon Sep 17 00:00:00 2001 From: Caelan Sayler Date: Tue, 13 May 2025 20:25:11 +0100 Subject: [PATCH] Refactor code and add tests --- src/lib-csharp/Sources/GitBase.cs | 2 +- src/lib-csharp/Sources/IUpdateSource.cs | 2 +- src/lib-csharp/UpdateManager.cs | 10 +- src/vpk/Velopack.Build/MSBuildLogger.cs | 53 +- src/vpk/Velopack.Build/PackTask.cs | 8 +- src/vpk/Velopack.Build/PublishTask.cs | 4 +- src/vpk/Velopack.Core/LoggerConsole.cs | 55 ++ .../Velopack.Core}/ReleaseEntry.cs | 4 +- .../Compression/DeltaPackage.cs | 1 + .../DeltaPackageTests.cs | 674 +++++++++--------- test/Velopack.Tests/ReleaseEntryTests.cs | 1 + 11 files changed, 404 insertions(+), 410 deletions(-) create mode 100644 src/vpk/Velopack.Core/LoggerConsole.cs rename src/{lib-csharp => vpk/Velopack.Core}/ReleaseEntry.cs (98%) diff --git a/src/lib-csharp/Sources/GitBase.cs b/src/lib-csharp/Sources/GitBase.cs index b13015e2..5641dc61 100644 --- a/src/lib-csharp/Sources/GitBase.cs +++ b/src/lib-csharp/Sources/GitBase.cs @@ -111,7 +111,7 @@ namespace Velopack.Sources protected abstract string GetAssetUrlFromName(T release, string assetName); /// - /// Provides a wrapper around which also contains a Git Release. + /// Provides a wrapper around which also contains a Git Release. /// protected internal record GitBaseAsset : VelopackAsset { diff --git a/src/lib-csharp/Sources/IUpdateSource.cs b/src/lib-csharp/Sources/IUpdateSource.cs index c25c5bdd..ad43e963 100644 --- a/src/lib-csharp/Sources/IUpdateSource.cs +++ b/src/lib-csharp/Sources/IUpdateSource.cs @@ -27,7 +27,7 @@ namespace Velopack.Sources /// metadata from this package may be provided to the remote server (such as package id, /// or cpu architecture) to ensure that the correct package is downloaded for this user. /// - /// An array of objects that are available for download + /// An array of objects that are available for download /// and are applicable to this user. Task GetReleaseFeed(IVelopackLogger logger, string? appId, string channel, Guid? stagingId = null, VelopackAsset? latestLocalRelease = null); diff --git a/src/lib-csharp/UpdateManager.cs b/src/lib-csharp/UpdateManager.cs index 7e1e7f76..1f2733f9 100644 --- a/src/lib-csharp/UpdateManager.cs +++ b/src/lib-csharp/UpdateManager.cs @@ -169,7 +169,6 @@ namespace Velopack } EnsureInstalled(); - var installedVer = CurrentVersion!; var matchingRemoteDelta = feed.Where(r => r.Type == VelopackAssetType.Delta && r.Version == latestRemoteFull.Version).FirstOrDefault(); if (matchingRemoteDelta == null) { @@ -328,7 +327,7 @@ namespace Velopack async x => { var targetFile = Locator.GetLocalPackagePath(x); double component = 0; - Log.Debug($"Downloading delta version {x.Version}"); + Log.Info($"Downloading delta {x.Version}"); await Source.DownloadReleaseEntry( Log, x, @@ -347,7 +346,8 @@ namespace Velopack Log.Debug($"Download complete for delta version {x.Version}"); }).ConfigureAwait(false); - Log.Info("All delta packages downloaded and verified, applying them to the base now."); + Log.Info("All delta packages downloaded and verified."); + Log.Info($"Applying {releasesToDownload.Length} patches to {updates.BaseRelease?.FileName}."); // applying deltas accounts for 70%-100% of progress var baseFile = Locator.GetLocalPackagePath(updates.BaseRelease!); @@ -365,10 +365,10 @@ namespace Velopack } var psi = new ProcessStartInfo(updateExe); - psi.AppendArgumentListSafe(args, out var _); + psi.AppendArgumentListSafe(args, out _); psi.CreateNoWindow = true; var p = psi.StartRedirectOutputToILogger(Log, VelopackLogLevel.Debug); - if (!p.WaitForExit((int)TimeSpan.FromMinutes(5).TotalMilliseconds)) { + if (!p.WaitForExit((int) TimeSpan.FromMinutes(5).TotalMilliseconds)) { p.Kill(); throw new TimeoutException("patch process timed out (5min)."); } diff --git a/src/vpk/Velopack.Build/MSBuildLogger.cs b/src/vpk/Velopack.Build/MSBuildLogger.cs index 8bc63207..1c40d2c0 100644 --- a/src/vpk/Velopack.Build/MSBuildLogger.cs +++ b/src/vpk/Velopack.Build/MSBuildLogger.cs @@ -10,7 +10,7 @@ using Task = System.Threading.Tasks.Task; namespace Velopack.Build; -public class MSBuildLogger(TaskLoggingHelper loggingHelper) : ILogger, IFancyConsole, IFancyConsoleProgress +public class MSBuildLogger(TaskLoggingHelper loggingHelper) : ILogger { private TaskLoggingHelper LoggingHelper { get; } = loggingHelper; @@ -19,31 +19,6 @@ public class MSBuildLogger(TaskLoggingHelper loggingHelper) : ILogger, IFancyCon throw new NotImplementedException(); } - public async Task ExecuteProgressAsync(Func action) - { - await action(this).ConfigureAwait(false); - } - - public async Task RunTask(string name, Func, Task> fn) - { - try { - await fn(x => { }).ConfigureAwait(false); - } catch (Exception ex) { - this.LogError(ex, "Error running task {taskName}", name); - throw; - } - } - - public async Task RunTask(string name, Func, Task> fn) - { - try { - return await fn(x => { }).ConfigureAwait(false); - } catch (Exception ex) { - this.LogError(ex, "Error running task {taskName}", name); - throw; - } - } - public bool IsEnabled(LogLevel logLevel) { return logLevel switch { @@ -60,6 +35,7 @@ public class MSBuildLogger(TaskLoggingHelper loggingHelper) : ILogger, IFancyCon if (exception != null) { message += " " + exception.Message; } + switch (logLevel) { case LogLevel.Trace: LoggingHelper.LogMessage(MessageImportance.Low, message); @@ -79,27 +55,4 @@ public class MSBuildLogger(TaskLoggingHelper loggingHelper) : ILogger, IFancyCon break; } } - - public void WriteTable(string tableName, IEnumerable> rows, bool hasHeaderRow = true) - { - LoggingHelper.LogMessage(tableName); - foreach (var row in rows) { - LoggingHelper.LogMessage(" " + String.Join(" ", row)); - } - } - - public System.Threading.Tasks.Task PromptYesNo(string prompt, bool? defaultValue = null, TimeSpan? timeout = null) - { - return Task.FromResult(true); - } - - public void WriteLine(string text = "") - { - Log(LogLevel.Information, 0, null, null, (object? state, Exception? exception) => text); - } - - public string EscapeMarkup(string text) - { - return text; - } -} +} \ No newline at end of file diff --git a/src/vpk/Velopack.Build/PackTask.cs b/src/vpk/Velopack.Build/PackTask.cs index 62989c8d..02644dd7 100644 --- a/src/vpk/Velopack.Build/PackTask.cs +++ b/src/vpk/Velopack.Build/PackTask.cs @@ -4,6 +4,7 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; using Microsoft.Build.Framework; +using Velopack.Core; using Velopack.Packaging; using Velopack.Packaging.Unix.Commands; using Velopack.Packaging.Windows.Commands; @@ -105,6 +106,7 @@ public class PackTask : MSBuildAsyncTask { //System.Diagnostics.Debugger.Launch(); try { + var console = new LoggerConsole(Logger); HelperFile.ClearSearchPaths(); var searchPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, "..", "..", "vendor")); HelperFile.AddSearchPath(searchPath); @@ -132,15 +134,15 @@ public class PackTask : MSBuildAsyncTask #pragma warning restore CS0618 // Type or member is obsolete } - var runner = new WindowsPackCommandRunner(Logger, Logger); + var runner = new WindowsPackCommandRunner(Logger, console); await runner.Run(options).ConfigureAwait(false); } else if (VelopackRuntimeInfo.IsOSX) { var options = this.ToOsxPackOptions(); - var runner = new OsxPackCommandRunner(Logger, Logger); + var runner = new OsxPackCommandRunner(Logger, console); await runner.Run(options).ConfigureAwait(false); } else if (VelopackRuntimeInfo.IsLinux) { var options = this.ToLinuxPackOptions(); - var runner = new LinuxPackCommandRunner(Logger, Logger); + var runner = new LinuxPackCommandRunner(Logger, console); await runner.Run(options).ConfigureAwait(false); } else { throw new NotSupportedException("Unsupported OS platform: " + VelopackRuntimeInfo.SystemOs.GetOsLongName()); diff --git a/src/vpk/Velopack.Build/PublishTask.cs b/src/vpk/Velopack.Build/PublishTask.cs index 19cb32d2..634730d7 100644 --- a/src/vpk/Velopack.Build/PublishTask.cs +++ b/src/vpk/Velopack.Build/PublishTask.cs @@ -3,6 +3,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Build.Framework; using Microsoft.Extensions.Logging; +using Velopack.Core; using Velopack.Flow; namespace Velopack.Build; @@ -44,7 +45,8 @@ public class PublishTask : MSBuildAsyncTask AllowInteractiveLogin = false, }; - var client = new VelopackFlowServiceClient(options, Logger, Logger); + var console = new LoggerConsole(Logger); + var client = new VelopackFlowServiceClient(options, Logger, console); if (!await client.LoginAsync(loginOptions, false, cancellationToken).ConfigureAwait(false)) { Logger.LogWarning("Not logged into Velopack Flow service, skipping publish. Please run vpk login."); return true; diff --git a/src/vpk/Velopack.Core/LoggerConsole.cs b/src/vpk/Velopack.Core/LoggerConsole.cs new file mode 100644 index 00000000..4e566739 --- /dev/null +++ b/src/vpk/Velopack.Core/LoggerConsole.cs @@ -0,0 +1,55 @@ +using Microsoft.Extensions.Logging; +using Velopack.Core.Abstractions; + +namespace Velopack.Core; + +public class LoggerConsole(ILogger log) : IFancyConsole, IFancyConsoleProgress +{ + public async Task ExecuteProgressAsync(Func action) + { + await action(this).ConfigureAwait(false); + } + + public async Task RunTask(string name, Func, Task> fn) + { + try { + await fn(x => { }).ConfigureAwait(false); + } catch (Exception ex) { + log.LogError(ex, "Error running task {taskName}", name); + throw; + } + } + + public async Task RunTask(string name, Func, Task> fn) + { + try { + return await fn(x => { }).ConfigureAwait(false); + } catch (Exception ex) { + log.LogError(ex, "Error running task {taskName}", name); + throw; + } + } + + public void WriteTable(string tableName, IEnumerable> rows, bool hasHeaderRow = true) + { + log.LogInformation(tableName); + foreach (var row in rows) { + log.LogInformation(" " + String.Join(" ", row)); + } + } + + public Task PromptYesNo(string prompt, bool? defaultValue = null, TimeSpan? timeout = null) + { + return Task.FromResult(true); + } + + public void WriteLine(string text = "") + { + log.LogInformation(text); + } + + public string EscapeMarkup(string text) + { + return text; + } +} \ No newline at end of file diff --git a/src/lib-csharp/ReleaseEntry.cs b/src/vpk/Velopack.Core/ReleaseEntry.cs similarity index 98% rename from src/lib-csharp/ReleaseEntry.cs rename to src/vpk/Velopack.Core/ReleaseEntry.cs index 1a525b9f..04388ec3 100644 --- a/src/lib-csharp/ReleaseEntry.cs +++ b/src/vpk/Velopack.Core/ReleaseEntry.cs @@ -13,7 +13,7 @@ using System.Threading.Tasks; using NuGet.Versioning; using Velopack.Util; -namespace Velopack +namespace Velopack.Core { /// /// Describes the requested release notes text format. @@ -146,7 +146,7 @@ namespace Velopack /// /// Create a new instance of . /// - protected internal ReleaseEntry(string sha1, string filename, long filesize, string baseUrl = null, string query = null, float? stagingPercentage = null) + public ReleaseEntry(string sha1, string filename, long filesize, string baseUrl = null, string query = null, float? stagingPercentage = null) { Contract.Requires(sha1 != null && sha1.Length == 40); Contract.Requires(filename != null); diff --git a/src/vpk/Velopack.Packaging/Compression/DeltaPackage.cs b/src/vpk/Velopack.Packaging/Compression/DeltaPackage.cs index 733e0b5a..11d9a8ae 100644 --- a/src/vpk/Velopack.Packaging/Compression/DeltaPackage.cs +++ b/src/vpk/Velopack.Packaging/Compression/DeltaPackage.cs @@ -1,6 +1,7 @@ #nullable enable using System.Text; using System.Text.RegularExpressions; +using Velopack.Core; using Velopack.Exceptions; using Velopack.Logging; using Velopack.Util; diff --git a/test/Velopack.Packaging.Tests/DeltaPackageTests.cs b/test/Velopack.Packaging.Tests/DeltaPackageTests.cs index b982952c..d09d4010 100644 --- a/test/Velopack.Packaging.Tests/DeltaPackageTests.cs +++ b/test/Velopack.Packaging.Tests/DeltaPackageTests.cs @@ -1,347 +1,327 @@ -//using System; -//using System.Collections.Generic; -//using System.IO; -//using System.Linq; -//using System.Threading.Tasks; -//using Squirrel.NuGet; -//using Squirrel; -//using Squirrel.SimpleSplat; -//using Squirrel.Tests.TestHelpers; -//using Xunit; -//using Xunit.Abstractions; -//using NuGet.Versioning; -//using Squirrel.CommandLine; - -//namespace Squirrel.Tests -//{ -// public class ApplyDeltaPackageTests : TestLoggingBase -// { -// public ApplyDeltaPackageTests(ITestOutputHelper log) : base(log) -// { -// } - -// [Fact] -// public void ApplyDeltaPackageSmokeTest() -// { -// var basePackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.0.0.0-full.nupkg"); -// var deltaPackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.1.0.0-delta.nupkg"); -// var expectedPackageFile = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.1.0.0-full.nupkg"); -// var outFile = Path.GetTempFileName() + ".nupkg"; - -// try { -// var deltaBuilder = new DeltaPackage(); -// deltaBuilder.ApplyDeltaPackage(basePackage, deltaPackage, outFile); - -// var result = new ZipPackage(outFile); -// var expected = new ZipPackage(expectedPackageFile); - -// result.Id.ShouldEqual(expected.Id); -// result.Version.ShouldEqual(expected.Version); - -// this.Log().Info("Expected file list:"); -// var expectedList = expected.Files.Select(x => x.Path).OrderBy(x => x).ToList(); -// expectedList.ForEach(x => this.Log().Info(x)); - -// this.Log().Info("Actual file list:"); -// var actualList = result.Files.Select(x => x.Path).OrderBy(x => x).ToList(); -// actualList.ForEach(x => this.Log().Info(x)); - -// Enumerable.Zip(expectedList, actualList, (e, a) => e == a) -// .All(x => x != false) -// .ShouldBeTrue(); -// } finally { -// if (File.Exists(outFile)) { -// File.Delete(outFile); -// } -// } -// } - -// [Fact] -// public void ApplyDeltaWithBothBsdiffAndNormalDiffDoesntFail() -// { -// var basePackage = IntegrationTestHelper.GetPath("fixtures", "slack-1.1.8-full.nupkg"); -// var deltaPackage = IntegrationTestHelper.GetPath("fixtures", "slack-1.2.0-delta.nupkg"); -// var outFile = Path.GetTempFileName() + ".nupkg"; - -// try { -// var deltaBuilder = new DeltaPackage(); -// deltaBuilder.ApplyDeltaPackage(basePackage, deltaPackage, outFile); - -// var result = new ZipPackage(outFile); - -// result.Id.ShouldEqual("slack"); -// result.Version.ShouldEqual(SemanticVersion.Parse("1.2.0")); -// } finally { -// if (File.Exists(outFile)) { -// File.Delete(outFile); -// } -// } -// } - -// [Fact] -// public void ApplyMultipleDeltasFast() -// { -// var basePackage = IntegrationTestHelper.GetPath("fixtures", "Clowd-3.4.287-full.nupkg"); -// var deltaPackage1 = IntegrationTestHelper.GetPath("fixtures", "Clowd-3.4.288-delta.nupkg"); -// var deltaPackage2 = IntegrationTestHelper.GetPath("fixtures", "Clowd-3.4.291-delta.nupkg"); -// var deltaPackage3 = IntegrationTestHelper.GetPath("fixtures", "Clowd-3.4.292-delta.nupkg"); - -// using var t1 = Utility.GetTempDirectory(out var appDir); -// using var t2 = Utility.GetTempDirectory(out var updateDir); - -// using var um = UpdateManagerTestImpl.FromLocalPackageTempDir(updateDir, "theApp", appDir); -// var pkgDir = um.Config.PackagesDir; - -// File.Copy(basePackage, Path.Combine(pkgDir, Path.GetFileName(basePackage))); -// File.Copy(deltaPackage1, Path.Combine(pkgDir, Path.GetFileName(deltaPackage1))); -// File.Copy(deltaPackage2, Path.Combine(pkgDir, Path.GetFileName(deltaPackage2))); -// File.Copy(deltaPackage3, Path.Combine(pkgDir, Path.GetFileName(deltaPackage3))); - -// var baseEntry = ReleaseEntry.GenerateFromFile(basePackage); - -// var toApply = new [] { -// ReleaseEntry.GenerateFromFile(deltaPackage1), -// ReleaseEntry.GenerateFromFile(deltaPackage2), -// ReleaseEntry.GenerateFromFile(deltaPackage3), -// }; - -// List progress = new List(); - -// var newEntry = um.createFullPackagesFromDeltas(toApply, baseEntry, progress.Add); - -// var outFile = Path.Combine(pkgDir, newEntry.Filename); -// var result = new ZipPackage(outFile); -// result.Id.ShouldEqual("Clowd"); -// result.Version.ShouldEqual(SemanticVersion.Parse("3.4.292")); -// } - -// [Fact(Skip = "Rewrite this test, the original uses too many heavyweight fixtures")] -// public void ApplyMultipleDeltaPackagesGeneratesCorrectHash() -// { -// Assert.Fail("Rewrite this test, the original uses too many heavyweight fixtures"); -// } -// } - -// public class CreateDeltaPackageTests : IEnableLogger -// { -// [Fact] -// public void CreateDeltaPackageIntegrationTest() -// { -// var basePackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Tests.0.1.0-pre.nupkg"); -// var newPackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Tests.0.2.0-pre.nupkg"); - -// var baseFixture = new ReleasePackageBuilder(basePackage); -// var fixture = new ReleasePackageBuilder(newPackage); - -// var tempFiles = Enumerable.Range(0, 3) -// .Select(_ => Path.GetTempPath() + Guid.NewGuid().ToString() + ".nupkg") -// .ToArray(); - -// try { -// baseFixture.CreateReleasePackage(tempFiles[0]); -// fixture.CreateReleasePackage(tempFiles[1]); - -// (new FileInfo(baseFixture.ReleasePackageFile)).Exists.ShouldBeTrue(); -// (new FileInfo(fixture.ReleasePackageFile)).Exists.ShouldBeTrue(); - -// var deltaBuilder = new DeltaPackageBuilder(); -// deltaBuilder.CreateDeltaPackage(baseFixture, fixture, tempFiles[2]); - -// var fullPkg = new ZipPackage(tempFiles[1]); -// var deltaPkg = new ZipPackage(tempFiles[2]); - -// // -// // Package Checks -// // - -// fullPkg.Id.ShouldEqual(deltaPkg.Id); -// fullPkg.Version.CompareTo(deltaPkg.Version).ShouldEqual(0); - -// // Delta packages should be smaller than the original! -// var fileInfos = tempFiles.Select(x => new FileInfo(x)).ToArray(); -// this.Log().Info("Base Size: {0}, Current Size: {1}, Delta Size: {2}", -// fileInfos[0].Length, fileInfos[1].Length, fileInfos[2].Length); - -// (fileInfos[2].Length - fileInfos[1].Length).ShouldBeLessThan(0); - -// // -// // File Checks -// /// - -// var deltaPkgFiles = deltaPkg.Files.ToList(); -// deltaPkgFiles.Count.ShouldBeGreaterThan(0); - -// this.Log().Info("Files in delta package:"); -// deltaPkgFiles.ForEach(x => this.Log().Info(x.Path)); - -// var newFilesAdded = new[] { -// "Newtonsoft.Json.dll", -// //"Refit.dll", -// //"Refit-Portable.dll", -// //"Castle.Core.dll", -// }.Select(x => x.ToLowerInvariant()); - -// // vNext adds a dependency on Refit -// newFilesAdded -// .All(x => deltaPkgFiles.Any(y => y.Path.ToLowerInvariant().Contains(x))) -// .ShouldBeTrue(); - -// // All the other files should be diffs and shasums -// deltaPkgFiles -// .Where(x => !newFilesAdded.Any(y => x.Path.ToLowerInvariant().Contains(y))) -// .All(x => x.Path.ToLowerInvariant().EndsWith("bsdiff") || x.Path.ToLowerInvariant().EndsWith("shasum")) -// .ShouldBeTrue(); - -// // Every .diff file should have a shasum file -// deltaPkg.Files.Any(x => x.Path.ToLowerInvariant().EndsWith(".bsdiff")).ShouldBeTrue(); -// deltaPkg.Files -// .Where(x => x.Path.ToLowerInvariant().EndsWith(".bsdiff")) -// .ForEach(x => { -// var lookingFor = x.Path.Replace(".bsdiff", ".shasum"); -// this.Log().Info("Looking for corresponding shasum file: {0}", lookingFor); -// deltaPkg.Files.Any(y => y.Path == lookingFor).ShouldBeTrue(); -// }); -// } finally { -// tempFiles.ForEach(File.Delete); -// } -// } - -// [Fact] -// public void WhenBasePackageIsNewerThanNewPackageThrowException() -// { -// var basePackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Tests.0.2.0-pre.nupkg"); -// var newPackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Tests.0.1.0-pre.nupkg"); - -// var baseFixture = new ReleasePackageBuilder(basePackage); -// var fixture = new ReleasePackageBuilder(newPackage); - -// var tempFiles = Enumerable.Range(0, 3) -// .Select(_ => Path.GetTempPath() + Guid.NewGuid().ToString() + ".nupkg") -// .ToArray(); - -// try { -// baseFixture.CreateReleasePackage(tempFiles[0]); -// fixture.CreateReleasePackage(tempFiles[1]); - -// (new FileInfo(baseFixture.ReleasePackageFile)).Exists.ShouldBeTrue(); -// (new FileInfo(fixture.ReleasePackageFile)).Exists.ShouldBeTrue(); - -// Assert.Throws(() => { -// var deltaBuilder = new DeltaPackageBuilder(); -// deltaBuilder.CreateDeltaPackage(baseFixture, fixture, tempFiles[2]); -// }); -// } finally { -// tempFiles.ForEach(File.Delete); -// } -// } - -// [Fact] -// public void WhenBasePackageReleaseIsNullThrowsException() -// { -// var basePackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.0.0.0.nupkg"); -// var newPackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.1.0.0.nupkg"); - -// var sourceDir = IntegrationTestHelper.GetPath("fixtures", "packages"); -// (new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue(); - -// var baseFixture = new ReleasePackageBuilder(basePackage); -// var fixture = new ReleasePackageBuilder(newPackage); - -// var tempFile = Path.GetTempPath() + Guid.NewGuid() + ".nupkg"; - -// try { -// Assert.Throws(() => { -// var deltaBuilder = new DeltaPackageBuilder(); -// deltaBuilder.CreateDeltaPackage(baseFixture, fixture, tempFile); -// }); -// } finally { -// File.Delete(tempFile); -// } -// } - -// [Fact] -// public void WhenBasePackageDoesNotExistThrowException() -// { -// var basePackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Tests.0.1.0-pre.nupkg"); -// var newPackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Tests.0.2.0-pre.nupkg"); - -// var baseFixture = new ReleasePackageBuilder(basePackage); -// var fixture = new ReleasePackageBuilder(newPackage); - -// var tempFiles = Enumerable.Range(0, 3) -// .Select(_ => Path.GetTempPath() + Guid.NewGuid().ToString() + ".nupkg") -// .ToArray(); - -// try { -// baseFixture.CreateReleasePackage(tempFiles[0]); -// fixture.CreateReleasePackage(tempFiles[1]); - -// (new FileInfo(baseFixture.ReleasePackageFile)).Exists.ShouldBeTrue(); -// (new FileInfo(fixture.ReleasePackageFile)).Exists.ShouldBeTrue(); - -// // NOW WATCH AS THE FILE DISAPPEARS -// File.Delete(baseFixture.ReleasePackageFile); - -// Assert.Throws(() => { -// var deltaBuilder = new DeltaPackageBuilder(); -// deltaBuilder.CreateDeltaPackage(baseFixture, fixture, tempFiles[2]); -// }); -// } finally { -// tempFiles.ForEach(File.Delete); -// } -// } - -// [Fact] -// public void WhenNewPackageDoesNotExistThrowException() -// { -// var basePackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Tests.0.1.0-pre.nupkg"); -// var newPackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Tests.0.2.0-pre.nupkg"); - -// var baseFixture = new ReleasePackageBuilder(basePackage); -// var fixture = new ReleasePackageBuilder(newPackage); - -// var tempFiles = Enumerable.Range(0, 3) -// .Select(_ => Path.GetTempPath() + Guid.NewGuid().ToString() + ".nupkg") -// .ToArray(); - -// try { -// baseFixture.CreateReleasePackage(tempFiles[0]); -// fixture.CreateReleasePackage(tempFiles[1]); - -// (new FileInfo(baseFixture.ReleasePackageFile)).Exists.ShouldBeTrue(); -// (new FileInfo(fixture.ReleasePackageFile)).Exists.ShouldBeTrue(); - -// // NOW WATCH AS THE FILE DISAPPEARS -// File.Delete(fixture.ReleasePackageFile); - -// Assert.Throws(() => { -// var deltaBuilder = new DeltaPackageBuilder(); -// deltaBuilder.CreateDeltaPackage(baseFixture, fixture, tempFiles[2]); -// }); -// } finally { -// tempFiles.ForEach(File.Delete); -// } -// } - -// [Fact] -// public void HandleBsDiffWithoutExtraData() -// { -// var baseFileData = new byte[] { 1, 1, 1, 1 }; -// var newFileData = new byte[] { 2, 1, 1, 1 }; - -// byte[] patchData; - -// using (var patchOut = new MemoryStream()) { -// Bsdiff.BinaryPatchUtility.Create(baseFileData, newFileData, patchOut); -// patchData = patchOut.ToArray(); -// } - -// using (var toPatch = new MemoryStream(baseFileData)) -// using (var patched = new MemoryStream()) { -// Bsdiff.BinaryPatchUtility.Apply(toPatch, () => new MemoryStream(patchData), patched); - -// Assert.Equal(newFileData, patched.ToArray()); -// } -// } -// } -//} +using Velopack.Core; +using Velopack.Packaging.Commands; +using Velopack.Util; + +namespace Velopack.Packaging.Tests; + +public class ApplyDeltaPackageTests(ITestOutputHelper output) +{ + // [Fact] + // public void ApplyDeltaPackageSmokeTest() + // { + // var basePackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.0.0.0-full.nupkg"); + // var deltaPackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.1.0.0-delta.nupkg"); + // var expectedPackageFile = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.1.0.0-full.nupkg"); + // var outFile = Path.GetTempFileName() + ".nupkg"; + // + // try { + // var deltaBuilder = new DeltaPackage(); + // deltaBuilder.ApplyDeltaPackage(basePackage, deltaPackage, outFile); + // + // var result = new ZipPackage(outFile); + // var expected = new ZipPackage(expectedPackageFile); + // + // result.Id.ShouldEqual(expected.Id); + // result.Version.ShouldEqual(expected.Version); + // + // this.Log().Info("Expected file list:"); + // var expectedList = expected.Files.Select(x => x.Path).OrderBy(x => x).ToList(); + // expectedList.ForEach(x => this.Log().Info(x)); + // + // this.Log().Info("Actual file list:"); + // var actualList = result.Files.Select(x => x.Path).OrderBy(x => x).ToList(); + // actualList.ForEach(x => this.Log().Info(x)); + // + // Enumerable.Zip(expectedList, actualList, (e, a) => e == a) + // .All(x => x != false) + // .ShouldBeTrue(); + // } finally { + // if (File.Exists(outFile)) { + // File.Delete(outFile); + // } + // } + // } + // + // [Fact] + // public void ApplyDeltaWithBothBsdiffAndNormalDiffDoesntFail() + // { + // var basePackage = IntegrationTestHelper.GetPath("fixtures", "slack-1.1.8-full.nupkg"); + // var deltaPackage = IntegrationTestHelper.GetPath("fixtures", "slack-1.2.0-delta.nupkg"); + // var outFile = Path.GetTempFileName() + ".nupkg"; + // + // try { + // var deltaBuilder = new DeltaPackage(); + // deltaBuilder.ApplyDeltaPackage(basePackage, deltaPackage, outFile); + // + // var result = new ZipPackage(outFile); + // + // result.Id.ShouldEqual("slack"); + // result.Version.ShouldEqual(SemanticVersion.Parse("1.2.0")); + // } finally { + // if (File.Exists(outFile)) { + // File.Delete(outFile); + // } + // } + // } + + [Fact] + public async Task ApplyMultipleDeltasFast() + { + var basePackage = PathHelper.GetFixture("Clowd-3.4.287-full.nupkg"); + var deltaPackage1 = PathHelper.GetFixture("Clowd-3.4.288-delta.nupkg"); + var deltaPackage2 = PathHelper.GetFixture("Clowd-3.4.291-delta.nupkg"); + var deltaPackage3 = PathHelper.GetFixture("Clowd-3.4.292-delta.nupkg"); + + using var t2 = TempUtil.GetTempDirectory(out var temp); + using var logger = output.BuildLoggerFor(); + var console = new LoggerConsole(logger); + + var runner = new DeltaPatchCommandRunner(logger, console); + await runner.Run( + new DeltaPatchOptions() { + BasePackage = basePackage, + OutputFile = Path.Combine(temp, "Clowd-3.4.292-full.nupkg"), + PatchFiles = [ + new FileInfo(deltaPackage1), + new FileInfo(deltaPackage2), + new FileInfo(deltaPackage3), + ] + }); + + // var newEntry = um.createFullPackagesFromDeltas(toApply, baseEntry, progress.Add); + // + // var outFile = Path.Combine(pkgDir, newEntry.Filename); + // var result = new ZipPackage(outFile); + // result.Id.ShouldEqual("Clowd"); + // result.Version.ShouldEqual(SemanticVersion.Parse("3.4.292")); + } + + // [Fact(Skip = "Rewrite this test, the original uses too many heavyweight fixtures")] + // public void ApplyMultipleDeltaPackagesGeneratesCorrectHash() + // { + // Assert.Fail("Rewrite this test, the original uses too many heavyweight fixtures"); + // } +} + +// public class CreateDeltaPackageTests : IEnableLogger +// { +// [Fact] +// public void CreateDeltaPackageIntegrationTest() +// { +// var basePackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Tests.0.1.0-pre.nupkg"); +// var newPackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Tests.0.2.0-pre.nupkg"); +// +// var baseFixture = new ReleasePackageBuilder(basePackage); +// var fixture = new ReleasePackageBuilder(newPackage); +// +// var tempFiles = Enumerable.Range(0, 3) +// .Select(_ => Path.GetTempPath() + Guid.NewGuid().ToString() + ".nupkg") +// .ToArray(); +// +// try { +// baseFixture.CreateReleasePackage(tempFiles[0]); +// fixture.CreateReleasePackage(tempFiles[1]); +// +// (new FileInfo(baseFixture.ReleasePackageFile)).Exists.ShouldBeTrue(); +// (new FileInfo(fixture.ReleasePackageFile)).Exists.ShouldBeTrue(); +// +// var deltaBuilder = new DeltaPackageBuilder(); +// deltaBuilder.CreateDeltaPackage(baseFixture, fixture, tempFiles[2]); +// +// var fullPkg = new ZipPackage(tempFiles[1]); +// var deltaPkg = new ZipPackage(tempFiles[2]); +// +// // +// // Package Checks +// // +// +// fullPkg.Id.ShouldEqual(deltaPkg.Id); +// fullPkg.Version.CompareTo(deltaPkg.Version).ShouldEqual(0); +// +// // Delta packages should be smaller than the original! +// var fileInfos = tempFiles.Select(x => new FileInfo(x)).ToArray(); +// this.Log().Info("Base Size: {0}, Current Size: {1}, Delta Size: {2}", +// fileInfos[0].Length, fileInfos[1].Length, fileInfos[2].Length); +// +// (fileInfos[2].Length - fileInfos[1].Length).ShouldBeLessThan(0); +// +// // +// // File Checks +// /// +// +// var deltaPkgFiles = deltaPkg.Files.ToList(); +// deltaPkgFiles.Count.ShouldBeGreaterThan(0); +// +// this.Log().Info("Files in delta package:"); +// deltaPkgFiles.ForEach(x => this.Log().Info(x.Path)); +// +// var newFilesAdded = new[] { +// "Newtonsoft.Json.dll", +// //"Refit.dll", +// //"Refit-Portable.dll", +// //"Castle.Core.dll", +// }.Select(x => x.ToLowerInvariant()); +// +// // vNext adds a dependency on Refit +// newFilesAdded +// .All(x => deltaPkgFiles.Any(y => y.Path.ToLowerInvariant().Contains(x))) +// .ShouldBeTrue(); +// +// // All the other files should be diffs and shasums +// deltaPkgFiles +// .Where(x => !newFilesAdded.Any(y => x.Path.ToLowerInvariant().Contains(y))) +// .All(x => x.Path.ToLowerInvariant().EndsWith("bsdiff") || x.Path.ToLowerInvariant().EndsWith("shasum")) +// .ShouldBeTrue(); +// +// // Every .diff file should have a shasum file +// deltaPkg.Files.Any(x => x.Path.ToLowerInvariant().EndsWith(".bsdiff")).ShouldBeTrue(); +// deltaPkg.Files +// .Where(x => x.Path.ToLowerInvariant().EndsWith(".bsdiff")) +// .ForEach(x => { +// var lookingFor = x.Path.Replace(".bsdiff", ".shasum"); +// this.Log().Info("Looking for corresponding shasum file: {0}", lookingFor); +// deltaPkg.Files.Any(y => y.Path == lookingFor).ShouldBeTrue(); +// }); +// } finally { +// tempFiles.ForEach(File.Delete); +// } +// } +// +// [Fact] +// public void WhenBasePackageIsNewerThanNewPackageThrowException() +// { +// var basePackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Tests.0.2.0-pre.nupkg"); +// var newPackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Tests.0.1.0-pre.nupkg"); +// +// var baseFixture = new ReleasePackageBuilder(basePackage); +// var fixture = new ReleasePackageBuilder(newPackage); +// +// var tempFiles = Enumerable.Range(0, 3) +// .Select(_ => Path.GetTempPath() + Guid.NewGuid().ToString() + ".nupkg") +// .ToArray(); +// +// try { +// baseFixture.CreateReleasePackage(tempFiles[0]); +// fixture.CreateReleasePackage(tempFiles[1]); +// +// (new FileInfo(baseFixture.ReleasePackageFile)).Exists.ShouldBeTrue(); +// (new FileInfo(fixture.ReleasePackageFile)).Exists.ShouldBeTrue(); +// +// Assert.Throws(() => { +// var deltaBuilder = new DeltaPackageBuilder(); +// deltaBuilder.CreateDeltaPackage(baseFixture, fixture, tempFiles[2]); +// }); +// } finally { +// tempFiles.ForEach(File.Delete); +// } +// } +// +// [Fact] +// public void WhenBasePackageReleaseIsNullThrowsException() +// { +// var basePackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.0.0.0.nupkg"); +// var newPackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.1.0.0.nupkg"); +// +// var sourceDir = IntegrationTestHelper.GetPath("fixtures", "packages"); +// (new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue(); +// +// var baseFixture = new ReleasePackageBuilder(basePackage); +// var fixture = new ReleasePackageBuilder(newPackage); +// +// var tempFile = Path.GetTempPath() + Guid.NewGuid() + ".nupkg"; +// +// try { +// Assert.Throws(() => { +// var deltaBuilder = new DeltaPackageBuilder(); +// deltaBuilder.CreateDeltaPackage(baseFixture, fixture, tempFile); +// }); +// } finally { +// File.Delete(tempFile); +// } +// } +// +// [Fact] +// public void WhenBasePackageDoesNotExistThrowException() +// { +// var basePackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Tests.0.1.0-pre.nupkg"); +// var newPackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Tests.0.2.0-pre.nupkg"); +// +// var baseFixture = new ReleasePackageBuilder(basePackage); +// var fixture = new ReleasePackageBuilder(newPackage); +// +// var tempFiles = Enumerable.Range(0, 3) +// .Select(_ => Path.GetTempPath() + Guid.NewGuid().ToString() + ".nupkg") +// .ToArray(); +// +// try { +// baseFixture.CreateReleasePackage(tempFiles[0]); +// fixture.CreateReleasePackage(tempFiles[1]); +// +// (new FileInfo(baseFixture.ReleasePackageFile)).Exists.ShouldBeTrue(); +// (new FileInfo(fixture.ReleasePackageFile)).Exists.ShouldBeTrue(); +// +// // NOW WATCH AS THE FILE DISAPPEARS +// File.Delete(baseFixture.ReleasePackageFile); +// +// Assert.Throws(() => { +// var deltaBuilder = new DeltaPackageBuilder(); +// deltaBuilder.CreateDeltaPackage(baseFixture, fixture, tempFiles[2]); +// }); +// } finally { +// tempFiles.ForEach(File.Delete); +// } +// } +// +// [Fact] +// public void WhenNewPackageDoesNotExistThrowException() +// { +// var basePackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Tests.0.1.0-pre.nupkg"); +// var newPackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Tests.0.2.0-pre.nupkg"); +// +// var baseFixture = new ReleasePackageBuilder(basePackage); +// var fixture = new ReleasePackageBuilder(newPackage); +// +// var tempFiles = Enumerable.Range(0, 3) +// .Select(_ => Path.GetTempPath() + Guid.NewGuid().ToString() + ".nupkg") +// .ToArray(); +// +// try { +// baseFixture.CreateReleasePackage(tempFiles[0]); +// fixture.CreateReleasePackage(tempFiles[1]); +// +// (new FileInfo(baseFixture.ReleasePackageFile)).Exists.ShouldBeTrue(); +// (new FileInfo(fixture.ReleasePackageFile)).Exists.ShouldBeTrue(); +// +// // NOW WATCH AS THE FILE DISAPPEARS +// File.Delete(fixture.ReleasePackageFile); +// +// Assert.Throws(() => { +// var deltaBuilder = new DeltaPackageBuilder(); +// deltaBuilder.CreateDeltaPackage(baseFixture, fixture, tempFiles[2]); +// }); +// } finally { +// tempFiles.ForEach(File.Delete); +// } +// } +// +// [Fact] +// public void HandleBsDiffWithoutExtraData() +// { +// var baseFileData = new byte[] { 1, 1, 1, 1 }; +// var newFileData = new byte[] { 2, 1, 1, 1 }; +// +// byte[] patchData; +// +// using (var patchOut = new MemoryStream()) { +// Bsdiff.BinaryPatchUtility.Create(baseFileData, newFileData, patchOut); +// patchData = patchOut.ToArray(); +// } +// +// using (var toPatch = new MemoryStream(baseFileData)) +// using (var patched = new MemoryStream()) { +// Bsdiff.BinaryPatchUtility.Apply(toPatch, () => new MemoryStream(patchData), patched); +// +// Assert.Equal(newFileData, patched.ToArray()); +// } +// } +// } \ No newline at end of file diff --git a/test/Velopack.Tests/ReleaseEntryTests.cs b/test/Velopack.Tests/ReleaseEntryTests.cs index 73c2623c..2be0aca3 100644 --- a/test/Velopack.Tests/ReleaseEntryTests.cs +++ b/test/Velopack.Tests/ReleaseEntryTests.cs @@ -1,6 +1,7 @@ #pragma warning disable CS0618 // Type or member is obsolete using System.Text; using NuGet.Versioning; +using Velopack.Core; using OldReleaseEntry = Velopack.Tests.OldSquirrel.ReleaseEntry; using OldSemanticVersion = Velopack.Tests.OldSquirrel.SemanticVersion;