mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-23 01:44:26 +08:00
Introduce HostLaunchPlan and refine launch flow
Add HostLaunchPlan/HostLaunchPlanBuilder to encapsulate host path, package root, working dir, forwarded args and env; add unit tests for builder. Refactor LauncherFlowCoordinator to use HostLaunchPlan when starting hosts, improve IPC handling and startup logic (shorter soft/hard timeouts, more frequent reconnects and shell status polling, activation recovery via existing host). Move argument formatting and environment setup into the plan, include package/working/args metadata in start attempts. Update Commands to prefer ProcessPath for launcher base directory. App and Program: start single-instance activation listener earlier and harden ActivateMainWindow to handle shell initialization state and return richer activation status codes. SingleInstanceService: signal listener readiness (ManualResetEventSlim) and wait briefly when starting, and dispose it. Various logging and minor error handling improvements.
This commit is contained in:
100
LanMountainDesktop.Tests/HostLaunchPlanBuilderTests.cs
Normal file
100
LanMountainDesktop.Tests/HostLaunchPlanBuilderTests.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using LanMountainDesktop.Launcher;
|
||||
using LanMountainDesktop.Launcher.Services;
|
||||
using LanMountainDesktop.Shared.Contracts.Launcher;
|
||||
using Xunit;
|
||||
|
||||
namespace LanMountainDesktop.Tests;
|
||||
|
||||
public sealed class HostLaunchPlanBuilderTests : IDisposable
|
||||
{
|
||||
private readonly string _testRoot;
|
||||
|
||||
public HostLaunchPlanBuilderTests()
|
||||
{
|
||||
_testRoot = Path.Combine(
|
||||
Path.GetTempPath(),
|
||||
"LanMountainDesktop.HostLaunchPlanTests",
|
||||
Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(_testRoot);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Build_UsesPackageRootAsWorkingDirectory_ForPublishedDeployment()
|
||||
{
|
||||
var packageRoot = Path.Combine(_testRoot, "package-root");
|
||||
var deployment = CreateDeployment(packageRoot, "app-0.8.5.7");
|
||||
var resultPath = Path.Combine(_testRoot, "launcher-result.json");
|
||||
var context = CommandContext.FromArgs(
|
||||
[
|
||||
"launch",
|
||||
"--app-root", packageRoot,
|
||||
"--result", resultPath,
|
||||
"--launch-source", "postinstall",
|
||||
"--custom-host-arg", "custom-value"
|
||||
]);
|
||||
var locator = new DeploymentLocator(packageRoot);
|
||||
var resolution = locator.ResolveHostExecutable(context);
|
||||
|
||||
var plan = HostLaunchPlanBuilder.Build(context, locator, resolution);
|
||||
|
||||
Assert.Equal(Path.GetFullPath(packageRoot), plan.PackageRoot);
|
||||
Assert.Equal(Path.GetFullPath(packageRoot), plan.WorkingDirectory);
|
||||
Assert.Equal(Path.Combine(deployment, GetExecutableName()), plan.HostPath);
|
||||
Assert.Contains("--launch-source", plan.Arguments);
|
||||
Assert.Contains("postinstall", plan.Arguments);
|
||||
Assert.Contains("--custom-host-arg", plan.Arguments);
|
||||
Assert.Contains("custom-value", plan.Arguments);
|
||||
Assert.DoesNotContain("--app-root", plan.Arguments);
|
||||
Assert.DoesNotContain(packageRoot, plan.Arguments);
|
||||
Assert.DoesNotContain("--result", plan.Arguments);
|
||||
Assert.DoesNotContain(resultPath, plan.Arguments);
|
||||
Assert.Contains($"--{LauncherIpcConstants.PackageRootEnvVar}={Path.GetFullPath(packageRoot)}", plan.Arguments);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Build_KeepsPathsWithSpacesAsSingleArgumentListTokens()
|
||||
{
|
||||
var packageRoot = Path.Combine(_testRoot, "package root with spaces");
|
||||
CreateDeployment(packageRoot, "app-0.8.5.7");
|
||||
var context = CommandContext.FromArgs(["launch", "--app-root", packageRoot]);
|
||||
var locator = new DeploymentLocator(packageRoot);
|
||||
var resolution = locator.ResolveHostExecutable(context);
|
||||
|
||||
var plan = HostLaunchPlanBuilder.Build(context, locator, resolution);
|
||||
|
||||
var packageRootArgument = $"--{LauncherIpcConstants.PackageRootEnvVar}={Path.GetFullPath(packageRoot)}";
|
||||
Assert.Contains(packageRootArgument, plan.Arguments);
|
||||
Assert.Equal(Path.GetFullPath(packageRoot), plan.EnvironmentVariables[LauncherIpcConstants.PackageRootEnvVar]);
|
||||
Assert.DoesNotContain(plan.Arguments, argument => argument.StartsWith("\"", StringComparison.Ordinal));
|
||||
Assert.Equal(Path.GetFullPath(packageRoot), plan.WorkingDirectory);
|
||||
}
|
||||
|
||||
private static string CreateDeployment(string packageRoot, string deploymentName)
|
||||
{
|
||||
var deployment = Path.Combine(packageRoot, deploymentName);
|
||||
Directory.CreateDirectory(deployment);
|
||||
File.WriteAllText(Path.Combine(deployment, GetExecutableName()), string.Empty);
|
||||
File.WriteAllText(Path.Combine(deployment, ".current"), string.Empty);
|
||||
File.WriteAllText(
|
||||
Path.Combine(deployment, "version.json"),
|
||||
"""
|
||||
{"Version":"0.8.5.7","Codename":"Administrate"}
|
||||
""");
|
||||
return deployment;
|
||||
}
|
||||
|
||||
private static string GetExecutableName()
|
||||
{
|
||||
return OperatingSystem.IsWindows()
|
||||
? "LanMountainDesktop.exe"
|
||||
: "LanMountainDesktop";
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (Directory.Exists(_testRoot))
|
||||
{
|
||||
Directory.Delete(_testRoot, recursive: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user