mirror of
https://github.com/velopack/velopack.git
synced 2025-10-25 15:19:22 +00:00
Add full update integration test
This commit is contained in:
@@ -32,6 +32,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Squirrel.Deployment", "src\
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Squirrel.Packaging.Tests", "test\Squirrel.Packaging.Tests\Squirrel.Packaging.Tests.csproj", "{175B06A5-5C09-4DAB-A6AF-C8A2257BD1B6}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Squirrel.Packaging.Tests", "test\Squirrel.Packaging.Tests\Squirrel.Packaging.Tests.csproj", "{175B06A5-5C09-4DAB-A6AF-C8A2257BD1B6}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApp", "test\TestApp\TestApp.csproj", "{784B5987-2E71-4AEE-81B9-E0CC7F1DBEB3}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -74,6 +76,10 @@ Global
|
|||||||
{175B06A5-5C09-4DAB-A6AF-C8A2257BD1B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{175B06A5-5C09-4DAB-A6AF-C8A2257BD1B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{175B06A5-5C09-4DAB-A6AF-C8A2257BD1B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{175B06A5-5C09-4DAB-A6AF-C8A2257BD1B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{175B06A5-5C09-4DAB-A6AF-C8A2257BD1B6}.Release|Any CPU.Build.0 = Release|Any CPU
|
{175B06A5-5C09-4DAB-A6AF-C8A2257BD1B6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{784B5987-2E71-4AEE-81B9-E0CC7F1DBEB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{784B5987-2E71-4AEE-81B9-E0CC7F1DBEB3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{784B5987-2E71-4AEE-81B9-E0CC7F1DBEB3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{784B5987-2E71-4AEE-81B9-E0CC7F1DBEB3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@@ -82,6 +88,7 @@ Global
|
|||||||
{98AEB048-E27D-42F4-9440-505B7F78BAFD} = {7AC3A776-B582-4B65-9D03-BD52332B5CA3}
|
{98AEB048-E27D-42F4-9440-505B7F78BAFD} = {7AC3A776-B582-4B65-9D03-BD52332B5CA3}
|
||||||
{519EAB50-47B8-425F-8B20-AB9548F220B4} = {7AC3A776-B582-4B65-9D03-BD52332B5CA3}
|
{519EAB50-47B8-425F-8B20-AB9548F220B4} = {7AC3A776-B582-4B65-9D03-BD52332B5CA3}
|
||||||
{175B06A5-5C09-4DAB-A6AF-C8A2257BD1B6} = {7AC3A776-B582-4B65-9D03-BD52332B5CA3}
|
{175B06A5-5C09-4DAB-A6AF-C8A2257BD1B6} = {7AC3A776-B582-4B65-9D03-BD52332B5CA3}
|
||||||
|
{784B5987-2E71-4AEE-81B9-E0CC7F1DBEB3} = {7AC3A776-B582-4B65-9D03-BD52332B5CA3}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {68CA987A-9BAB-4C75-8EEB-4596BA6BBD07}
|
SolutionGuid = {68CA987A-9BAB-4C75-8EEB-4596BA6BBD07}
|
||||||
|
|||||||
@@ -28,7 +28,9 @@ fn root_command() -> Command {
|
|||||||
.about("Applies a staged / prepared update, installing prerequisite runtimes if necessary")
|
.about("Applies a staged / prepared update, installing prerequisite runtimes if necessary")
|
||||||
.arg(arg!(-r --restart "Restart the application after the update"))
|
.arg(arg!(-r --restart "Restart the application after the update"))
|
||||||
.arg(arg!(-w --wait "Wait for the parent process to terminate before applying the update"))
|
.arg(arg!(-w --wait "Wait for the parent process to terminate before applying the update"))
|
||||||
// .arg(arg!(-p --pkg <FILE> "Update package to apply").value_parser(value_parser!(PathBuf)))
|
.arg(arg!(-p --package <FILE> "Update package to apply").value_parser(value_parser!(PathBuf)))
|
||||||
|
.arg(arg!([EXE_NAME] "The optional name of the binary to execute"))
|
||||||
|
.arg(arg!([EXE_ARGS] "Arguments to pass to the started executable. Must be preceeded by '--'.").required(false).last(true).num_args(0..))
|
||||||
)
|
)
|
||||||
.subcommand(Command::new("start")
|
.subcommand(Command::new("start")
|
||||||
.about("Starts the currently installed version of the application")
|
.about("Starts the currently installed version of the application")
|
||||||
|
|||||||
@@ -287,7 +287,7 @@ namespace Squirrel
|
|||||||
|
|
||||||
private static string GetNextTempName(string tempDir)
|
private static string GetNextTempName(string tempDir)
|
||||||
{
|
{
|
||||||
for (int i = 1; i < 10000; i++) {
|
for (int i = 1; i < 1000; i++) {
|
||||||
string name = "temp." + i;
|
string name = "temp." + i;
|
||||||
var target = Path.Combine(tempDir, name);
|
var target = Path.Combine(tempDir, name);
|
||||||
|
|
||||||
@@ -311,7 +311,7 @@ namespace Squirrel
|
|||||||
}
|
}
|
||||||
|
|
||||||
throw new Exception(
|
throw new Exception(
|
||||||
"Unable to find free temp path. Has the temp directory exceeded it's maximum number of items? (10000)");
|
"Unable to find free temp path. Has the temp directory exceeded it's maximum number of items? (1000)");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IDisposable GetTempDirectory(out string newTempDirectory)
|
public static IDisposable GetTempDirectory(out string newTempDirectory)
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ namespace Squirrel.Locators
|
|||||||
/// <summary> The currently installed version of the application, or null if the app is not installed. </summary>
|
/// <summary> The currently installed version of the application, or null if the app is not installed. </summary>
|
||||||
public SemanticVersion CurrentlyInstalledVersion { get; }
|
public SemanticVersion CurrentlyInstalledVersion { get; }
|
||||||
|
|
||||||
|
/// <summary> The path from <see cref="AppContentDir"/> to this executable. </summary>
|
||||||
|
public string ThisExeRelativePath { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Finds .nupkg files in the PackagesDir and returns a list of ReleaseEntryName objects.
|
/// Finds .nupkg files in the PackagesDir and returns a list of ReleaseEntryName objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ namespace Squirrel.Locators
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static SquirrelLocator GetDefault(ILogger logger)
|
public static SquirrelLocator GetDefault(ILogger logger)
|
||||||
{
|
{
|
||||||
|
if (_current != null)
|
||||||
|
return _current;
|
||||||
|
|
||||||
if (SquirrelRuntimeInfo.IsWindows)
|
if (SquirrelRuntimeInfo.IsWindows)
|
||||||
return _current ??= new WindowsSquirrelLocator(logger);
|
return _current ??= new WindowsSquirrelLocator(logger);
|
||||||
|
|
||||||
@@ -48,6 +51,18 @@ namespace Squirrel.Locators
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public abstract string AppContentDir { get; }
|
public abstract string AppContentDir { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public virtual string ThisExeRelativePath {
|
||||||
|
get {
|
||||||
|
var path = SquirrelRuntimeInfo.EntryExePath;
|
||||||
|
if (path.StartsWith(AppContentDir, StringComparison.OrdinalIgnoreCase)) {
|
||||||
|
return path.Substring(AppContentDir.Length + 1);
|
||||||
|
} else {
|
||||||
|
throw new InvalidOperationException(path + " is not contained in " + AppContentDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public abstract SemanticVersion CurrentlyInstalledVersion { get; }
|
public abstract SemanticVersion CurrentlyInstalledVersion { get; }
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
@@ -21,7 +22,7 @@ namespace Squirrel
|
|||||||
|
|
||||||
public virtual bool IsInstalled => Locator.CurrentlyInstalledVersion != null;
|
public virtual bool IsInstalled => Locator.CurrentlyInstalledVersion != null;
|
||||||
|
|
||||||
public virtual bool IsPendingRestart {
|
public virtual bool IsUpdatePendingRestart {
|
||||||
get {
|
get {
|
||||||
var latestLocal = Locator.GetLatestLocalPackage();
|
var latestLocal = Locator.GetLatestLocalPackage();
|
||||||
if (latestLocal != null && latestLocal.Version > CurrentVersion)
|
if (latestLocal != null && latestLocal.Version > CurrentVersion)
|
||||||
@@ -38,21 +39,11 @@ namespace Squirrel
|
|||||||
|
|
||||||
protected ISquirrelLocator Locator { get; }
|
protected ISquirrelLocator Locator { get; }
|
||||||
|
|
||||||
public UpdateManager(string urlOrPath, string channel = null, ILogger logger = null)
|
|
||||||
: this(urlOrPath, channel, logger, null)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public UpdateManager(string urlOrPath, string channel = null, ILogger logger = null, ISquirrelLocator locator = null)
|
public UpdateManager(string urlOrPath, string channel = null, ILogger logger = null, ISquirrelLocator locator = null)
|
||||||
: this(CreateSimpleSource(urlOrPath, channel, logger), logger, locator)
|
: this(CreateSimpleSource(urlOrPath, channel, logger), logger, locator)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public UpdateManager(IUpdateSource source, ILogger logger = null)
|
|
||||||
: this(source, logger, null)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public UpdateManager(IUpdateSource source, ILogger logger = null, ISquirrelLocator locator = null)
|
public UpdateManager(IUpdateSource source, ILogger logger = null, ISquirrelLocator locator = null)
|
||||||
{
|
{
|
||||||
if (source == null) {
|
if (source == null) {
|
||||||
@@ -117,13 +108,13 @@ namespace Squirrel
|
|||||||
return new UpdateInfo(latestRemoteFull, latestLocalFull, deltas);
|
return new UpdateInfo(latestRemoteFull, latestLocalFull, deltas);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DownloadAndPrepareUpdates(UpdateInfo updates, Action<int> progress = null, bool ignoreDeltas = false)
|
public void DownloadUpdates(UpdateInfo updates, Action<int> progress = null, bool ignoreDeltas = false)
|
||||||
{
|
{
|
||||||
DownloadAndPrepareUpdatesAsync(updates, progress, ignoreDeltas)
|
DownloadUpdatesAsync(updates, progress, ignoreDeltas)
|
||||||
.ConfigureAwait(false).GetAwaiter().GetResult();
|
.ConfigureAwait(false).GetAwaiter().GetResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual async Task DownloadAndPrepareUpdatesAsync(
|
public virtual async Task DownloadUpdatesAsync(
|
||||||
UpdateInfo updates, Action<int> progress = null, bool ignoreDeltas = false, CancellationToken cancelToken = default)
|
UpdateInfo updates, Action<int> progress = null, bool ignoreDeltas = false, CancellationToken cancelToken = default)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@@ -204,14 +195,62 @@ namespace Squirrel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ExitAndApplyUpdates()
|
public void ApplyUpdatesAndExit(bool silent = false)
|
||||||
{
|
{
|
||||||
|
RunApplyUpdates(silent, false, null);
|
||||||
|
Environment.Exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WaitForExitAndApplyUpdates(bool restart, string[] arguments = null)
|
public void ApplyUpdatesAndRestart(bool silent = false, string[] restartArgs = null)
|
||||||
{
|
{
|
||||||
var updateArgs = new string[]{ "--update" };
|
RunApplyUpdates(silent, true, restartArgs);
|
||||||
|
Environment.Exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void RunApplyUpdates(bool silent, bool restart, string[] restartArgs)
|
||||||
|
{
|
||||||
|
var psi = new ProcessStartInfo() {
|
||||||
|
CreateNoWindow = true,
|
||||||
|
FileName = Locator.UpdateExePath,
|
||||||
|
WorkingDirectory = Path.GetDirectoryName(Locator.UpdateExePath),
|
||||||
|
};
|
||||||
|
|
||||||
|
#if NET5_0_OR_GREATER
|
||||||
|
var args = psi.ArgumentList;
|
||||||
|
#else
|
||||||
|
var args = new List<string>();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (silent) args.Add("--silent");
|
||||||
|
args.Add("apply");
|
||||||
|
args.Add("--wait");
|
||||||
|
if (restart) args.Add("--restart");
|
||||||
|
|
||||||
|
try {
|
||||||
|
args.Add(Locator.ThisExeRelativePath); // optional
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Log.Error(ex, "Failed to find relative path to this executable.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (restart && restartArgs != null && restartArgs.Length > 0) {
|
||||||
|
args.Add("--");
|
||||||
|
foreach (var a in restartArgs) {
|
||||||
|
args.Add(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !NET5_0_OR_GREATER
|
||||||
|
psi.Arguments = String.Join(" ", args);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
var p = Process.Start(psi);
|
||||||
|
Thread.Sleep(300);
|
||||||
|
if (p == null) {
|
||||||
|
throw new Exception("Failed to launch Update.exe process.");
|
||||||
|
}
|
||||||
|
if (p.HasExited) {
|
||||||
|
throw new Exception($"Update.exe process exited too soon ({p.ExitCode}).");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual async Task DownloadAndApplyDeltaUpdates(string extractedBasePackage, UpdateInfo updates, Action<int> progress)
|
protected virtual async Task DownloadAndApplyDeltaUpdates(string extractedBasePackage, UpdateInfo updates, Action<int> progress)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using System.Globalization;
|
|||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
using NuGet.Packaging;
|
using NuGet.Packaging;
|
||||||
using Squirrel.Compression;
|
using Squirrel.Compression;
|
||||||
@@ -223,9 +224,7 @@ public class WindowsPackTests
|
|||||||
var setupPath1 = Path.Combine(tmpReleaseDir, $"{id}-Setup-[win-x64].exe");
|
var setupPath1 = Path.Combine(tmpReleaseDir, $"{id}-Setup-[win-x64].exe");
|
||||||
Assert.True(File.Exists(setupPath1));
|
Assert.True(File.Exists(setupPath1));
|
||||||
|
|
||||||
var result = PlatformUtil.InvokeProcess(setupPath1, new string[] { "--nocolor", "--silent", "--installto", tmpInstallDir }, Environment.CurrentDirectory, CancellationToken.None);
|
RunProcess(setupPath1, new[] { "--nocolor", "--silent", "--installto", tmpInstallDir }, Environment.CurrentDirectory, logger);
|
||||||
logger.Info(result.StdOutput);
|
|
||||||
Assert.Equal(0, result.ExitCode);
|
|
||||||
|
|
||||||
var updatePath = Path.Combine(tmpInstallDir, "Update.exe");
|
var updatePath = Path.Combine(tmpInstallDir, "Update.exe");
|
||||||
Assert.True(File.Exists(updatePath));
|
Assert.True(File.Exists(updatePath));
|
||||||
@@ -252,9 +251,7 @@ public class WindowsPackTests
|
|||||||
var date = DateTime.Now.ToString("yyyyMMdd", CultureInfo.InvariantCulture);
|
var date = DateTime.Now.ToString("yyyyMMdd", CultureInfo.InvariantCulture);
|
||||||
Assert.Equal(date, installDate.Trim('\0'));
|
Assert.Equal(date, installDate.Trim('\0'));
|
||||||
|
|
||||||
var result2 = PlatformUtil.InvokeProcess(updatePath, new string[] { "--nocolor", "--silent", "--uninstall" }, Environment.CurrentDirectory, CancellationToken.None);
|
RunProcess(updatePath, new string[] { "--nocolor", "--silent", "--uninstall" }, Environment.CurrentDirectory, logger);
|
||||||
logger.Info(result2.StdOutput);
|
|
||||||
Assert.Equal(0, result2.ExitCode);
|
|
||||||
|
|
||||||
Assert.False(File.Exists(shortcutPath));
|
Assert.False(File.Exists(shortcutPath));
|
||||||
Assert.False(File.Exists(appPath));
|
Assert.False(File.Exists(appPath));
|
||||||
@@ -264,4 +261,143 @@ public class WindowsPackTests
|
|||||||
Assert.Null(key2);
|
Assert.Null(key2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[SkippableFact]
|
||||||
|
public void TestPackedAppCanDeltaUpdateToLatest()
|
||||||
|
{
|
||||||
|
Skip.IfNot(SquirrelRuntimeInfo.IsWindows);
|
||||||
|
using var logger = _output.BuildLoggerFor<WindowsPackTests>();
|
||||||
|
using var _1 = Utility.GetTempDirectory(out var releaseDir);
|
||||||
|
using var _2 = Utility.GetTempDirectory(out var installDir);
|
||||||
|
|
||||||
|
// pack v1
|
||||||
|
PackTestApp("1.0.0", "version 1 test", releaseDir, logger);
|
||||||
|
|
||||||
|
// install app
|
||||||
|
var setupPath1 = Path.Combine(releaseDir, $"{TEST_APP_ID}-Setup-[win-x64].exe");
|
||||||
|
RunProcess(setupPath1, new string[] { "--nocolor", "--silent", "--installto", installDir }, Environment.GetFolderPath(Environment.SpecialFolder.Desktop), logger);
|
||||||
|
|
||||||
|
// check app installed correctly
|
||||||
|
var appPath = Path.Combine(installDir, "current", "TestApp.exe");
|
||||||
|
Assert.True(File.Exists(appPath));
|
||||||
|
var argsPath = Path.Combine(installDir, "current", "args.txt");
|
||||||
|
Assert.True(File.Exists(argsPath));
|
||||||
|
var argsContent = File.ReadAllText(argsPath).Trim();
|
||||||
|
Assert.Equal("--squirrel-install 1.0.0", argsContent);
|
||||||
|
|
||||||
|
// check app output
|
||||||
|
var chk1test = RunProcess(appPath, new string[] { "test" }, installDir, logger);
|
||||||
|
Assert.Equal("version 1 test", chk1test);
|
||||||
|
var chk1version = RunProcess(appPath, new string[] { "version" }, installDir, logger);
|
||||||
|
Assert.EndsWith(Environment.NewLine + "1.0.0", chk1version);
|
||||||
|
var chk1check = RunProcess(appPath, new string[] { "check", releaseDir }, installDir, logger);
|
||||||
|
Assert.EndsWith(Environment.NewLine + "no updates", chk1check);
|
||||||
|
|
||||||
|
// pack v2
|
||||||
|
PackTestApp("2.0.0", "version 2 test", releaseDir, logger);
|
||||||
|
|
||||||
|
// check can find v2 update
|
||||||
|
var chk2check = RunProcess(appPath, new string[] { "check", releaseDir }, installDir, logger);
|
||||||
|
Assert.EndsWith(Environment.NewLine + "update: 2.0.0", chk2check);
|
||||||
|
|
||||||
|
// pack v3
|
||||||
|
PackTestApp("3.0.0", "version 3 test", releaseDir, logger);
|
||||||
|
|
||||||
|
// perform full update, check that we get v3
|
||||||
|
// apply should fail if there's not an update downloaded
|
||||||
|
RunProcess(appPath, new string[] { "apply", releaseDir }, installDir, logger, -1);
|
||||||
|
RunProcess(appPath, new string[] { "download", releaseDir }, installDir, logger);
|
||||||
|
RunProcess(appPath, new string[] { "apply", releaseDir }, installDir, logger);
|
||||||
|
|
||||||
|
// check app output
|
||||||
|
var chk3test = RunProcess(appPath, new string[] { "test" }, installDir, logger);
|
||||||
|
Assert.Equal("version 3 test", chk3test);
|
||||||
|
var chk3version = RunProcess(appPath, new string[] { "version" }, installDir, logger);
|
||||||
|
Assert.EndsWith(Environment.NewLine + "3.0.0", chk3version);
|
||||||
|
var ch3check2 = RunProcess(appPath, new string[] { "check", releaseDir }, installDir, logger);
|
||||||
|
Assert.EndsWith(Environment.NewLine + "no updates", ch3check2);
|
||||||
|
|
||||||
|
// check new obsoleted/updated hooks have run
|
||||||
|
var argsContentv3 = File.ReadAllText(argsPath).Trim();
|
||||||
|
Assert.Contains("--squirrel-install 1.0.0", argsContent);
|
||||||
|
Assert.Contains("--squirrel-obsoleted 1.0.0", argsContent);
|
||||||
|
Assert.Contains("--squirrel-updated 3.0.0", argsContent);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//var ch3download = RunProcess(appPath, new string[] { "check", releaseDir }, installDir, logger);
|
||||||
|
//logger.Info(ch3download.StdOutput);
|
||||||
|
//Assert.Equal(0, ch3download.ExitCode);
|
||||||
|
//Assert.Equal("update: 3.0.0", ch3download.StdOutput.Trim());
|
||||||
|
//var ch3apply = RunProcess(appPath, new string[] { "check", releaseDir }, installDir, logger);
|
||||||
|
//logger.Info(ch3apply.StdOutput);
|
||||||
|
//Assert.Equal(0, ch3apply.ExitCode);
|
||||||
|
//Assert.Equal("update: 3.0.0", ch3apply.StdOutput.Trim());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// uninstall
|
||||||
|
var updatePath = Path.Combine(installDir, "Update.exe");
|
||||||
|
RunProcess(updatePath, new string[] { "--nocolor", "--silent", "--uninstall" }, Environment.CurrentDirectory, logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
const string TEST_APP_ID = "Test.Squirrel-App";
|
||||||
|
|
||||||
|
private string RunProcess(string exe, string[] args, string workingDir, ILogger logger, int exitCode = 0)
|
||||||
|
{
|
||||||
|
var psi = new ProcessStartInfo(exe);
|
||||||
|
psi.WorkingDirectory = workingDir;
|
||||||
|
psi.CreateNoWindow = true;
|
||||||
|
psi.RedirectStandardOutput = true;
|
||||||
|
psi.RedirectStandardError = true;
|
||||||
|
psi.ArgumentList.AddRange(args);
|
||||||
|
var p = Process.Start(psi);
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
p.BeginErrorReadLine();
|
||||||
|
p.BeginOutputReadLine();
|
||||||
|
p.OutputDataReceived += (s, e) => { sb.AppendLine(e.Data); logger.Debug(e.Data); };
|
||||||
|
p.ErrorDataReceived += (s, e) => { sb.AppendLine(e.Data); logger.Debug(e.Data); };
|
||||||
|
p.WaitForExit();
|
||||||
|
|
||||||
|
Assert.Equal(exitCode, p.ExitCode);
|
||||||
|
return sb.ToString().Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PackTestApp(string version, string testString, string releaseDir, ILogger logger)
|
||||||
|
{
|
||||||
|
var projDir = GetPath("TestApp");
|
||||||
|
var testStringFile = Path.Combine(projDir, "Const.cs");
|
||||||
|
|
||||||
|
var oldText = File.ReadAllText(testStringFile);
|
||||||
|
File.WriteAllText(testStringFile, $"class Const {{ public const string TEST_STRING = \"{testString}\"; }}");
|
||||||
|
var args = new string[] { "publish", "--no-self-contained", "-c", "Release", "-r", "win-x64", "-o", "publish" };
|
||||||
|
RunProcess("dotnet", args, projDir, logger);
|
||||||
|
File.WriteAllText(testStringFile, oldText);
|
||||||
|
|
||||||
|
var options = new WindowsPackOptions {
|
||||||
|
EntryExecutableName = "TestApp.exe",
|
||||||
|
ReleaseDir = new DirectoryInfo(releaseDir),
|
||||||
|
PackId = TEST_APP_ID,
|
||||||
|
PackVersion = version,
|
||||||
|
TargetRuntime = RID.Parse("win-x64"),
|
||||||
|
PackDirectory = Path.Combine(projDir, "publish"),
|
||||||
|
};
|
||||||
|
|
||||||
|
var runner = new WindowsPackCommandRunner(logger);
|
||||||
|
runner.Pack(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetPath(params string[] paths)
|
||||||
|
{
|
||||||
|
var ret = GetIntegrationTestRootDirectory();
|
||||||
|
return (new FileInfo(paths.Aggregate(ret, Path.Combine))).FullName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetIntegrationTestRootDirectory()
|
||||||
|
{
|
||||||
|
var st = new StackFrame(true);
|
||||||
|
var di = new DirectoryInfo(Path.Combine(Path.GetDirectoryName(st.GetFileName()), ".."));
|
||||||
|
return di.FullName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ namespace Squirrel.Tests
|
|||||||
Assert.True(SemanticVersion.Parse(version) == info.TargetFullRelease.Version);
|
Assert.True(SemanticVersion.Parse(version) == info.TargetFullRelease.Version);
|
||||||
Assert.Equal(0, info.DeltasToTarget.Count());
|
Assert.Equal(0, info.DeltasToTarget.Count());
|
||||||
|
|
||||||
um.DownloadAndPrepareUpdates(info);
|
um.DownloadUpdates(info);
|
||||||
|
|
||||||
var target = Path.Combine(packagesDir, $"{id}-{version}-full.nupkg");
|
var target = Path.Combine(packagesDir, $"{id}-{version}-full.nupkg");
|
||||||
Assert.True(File.Exists(target));
|
Assert.True(File.Exists(target));
|
||||||
@@ -203,7 +203,7 @@ namespace Squirrel.Tests
|
|||||||
Assert.Equal(3, info.DeltasToTarget.Count());
|
Assert.Equal(3, info.DeltasToTarget.Count());
|
||||||
Assert.NotNull(info.BaseRelease);
|
Assert.NotNull(info.BaseRelease);
|
||||||
|
|
||||||
await um.DownloadAndPrepareUpdatesAsync(info);
|
await um.DownloadUpdatesAsync(info);
|
||||||
var target = Path.Combine(packagesDir, $"{id}-{toVersion}-full.nupkg");
|
var target = Path.Combine(packagesDir, $"{id}-{toVersion}-full.nupkg");
|
||||||
Assert.True(File.Exists(target));
|
Assert.True(File.Exists(target));
|
||||||
}
|
}
|
||||||
|
|||||||
19
test/TestApp/ConsoleLogger.cs
Normal file
19
test/TestApp/ConsoleLogger.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
class ConsoleLogger : ILogger
|
||||||
|
{
|
||||||
|
public IDisposable BeginScope<TState>(TState state) where TState : notnull
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsEnabled(LogLevel logLevel)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
|
||||||
|
{
|
||||||
|
Console.WriteLine(formatter(state, exception));
|
||||||
|
}
|
||||||
|
}
|
||||||
1
test/TestApp/Const.cs
Normal file
1
test/TestApp/Const.cs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
class Const { public const string TEST_STRING = "Hello, World!"; }
|
||||||
64
test/TestApp/Program.cs
Normal file
64
test/TestApp/Program.cs
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
using Squirrel;
|
||||||
|
using Squirrel.Locators;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (args.Length >= 1 && args[0].StartsWith("--squirrel")) {
|
||||||
|
// squirrel hooks
|
||||||
|
File.AppendAllText(Path.Combine(AppContext.BaseDirectory, "args.txt"), String.Join(" ", args) + Environment.NewLine);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.Length == 1 && args[0] == "version") {
|
||||||
|
var locator = SquirrelLocator.GetDefault(new ConsoleLogger());
|
||||||
|
Console.WriteLine(locator.CurrentlyInstalledVersion);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.Length == 1 && args[0] == "test") {
|
||||||
|
Console.WriteLine(Const.TEST_STRING);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.Length == 2) {
|
||||||
|
if (args[0] == "check") {
|
||||||
|
var um = new UpdateManager(args[1], null, new ConsoleLogger());
|
||||||
|
var info = um.CheckForUpdates();
|
||||||
|
if (info == null) {
|
||||||
|
Console.WriteLine("no updates");
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
Console.WriteLine("update: " + info.TargetFullRelease.Version);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args[0] == "download") {
|
||||||
|
var um = new UpdateManager(args[1], null, new ConsoleLogger());
|
||||||
|
var info = um.CheckForUpdates();
|
||||||
|
if (info == null) {
|
||||||
|
Console.WriteLine("no updates");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
um.DownloadUpdates(info, (x) => Console.WriteLine(x));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args[0] == "apply") {
|
||||||
|
var um = new UpdateManager(args[1], null, new ConsoleLogger());
|
||||||
|
if (!um.IsUpdatePendingRestart) {
|
||||||
|
Console.WriteLine("not pending restart");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
Console.WriteLine("applying...");
|
||||||
|
um.ApplyUpdatesAndExit();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Console.WriteLine("exception: " + ex.ToString());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("Invalid args: " + String.Join(", ", args));
|
||||||
|
return -1;
|
||||||
13
test/TestApp/TestApp.csproj
Normal file
13
test/TestApp/TestApp.csproj
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\src\Squirrel\Squirrel.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
Reference in New Issue
Block a user