fix.正在修复 .NET运行时问题

This commit is contained in:
lincube
2026-05-24 23:12:48 +08:00
parent edf3d82cc9
commit fd3a193e68
16 changed files with 1263 additions and 176 deletions

View File

@@ -0,0 +1,74 @@
using LanMountainDesktop.Launcher.Services;
using LanMountainDesktop.Launcher.Services.AirApp;
using Xunit;
namespace LanMountainDesktop.Tests;
public sealed class AirAppProcessStarterRuntimeTests : IDisposable
{
private readonly string _root;
public AirAppProcessStarterRuntimeTests()
{
_root = Path.Combine(Path.GetTempPath(), "LanMountainDesktop.AirAppProcessStarterRuntimeTests", Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(_root);
}
[Fact]
public void CreateStartInfo_UsesPackagedExecutable_WhenExeExists()
{
var hostPath = Path.Combine(_root, OperatingSystem.IsWindows()
? "LanMountainDesktop.AirAppHost.exe"
: "LanMountainDesktop.AirAppHost");
File.WriteAllText(hostPath, string.Empty);
var startInfo = AirAppProcessStarter.CreateStartInfo(hostPath);
Assert.Equal(hostPath, startInfo.FileName);
Assert.Empty(startInfo.ArgumentList);
}
[Fact]
public void CreateStartInfo_UsesArchitectureMatchedDotnetHost_ForDllFallbackOnWindows()
{
if (!OperatingSystem.IsWindows())
{
return;
}
var programFiles = Path.Combine(_root, "ProgramFiles");
var dotnetRoot = Path.Combine(programFiles, "dotnet");
Directory.CreateDirectory(dotnetRoot);
var dotnetHost = Path.Combine(dotnetRoot, "dotnet.exe");
File.WriteAllText(dotnetHost, string.Empty);
Directory.CreateDirectory(Path.Combine(
dotnetRoot,
"shared",
DotNetRuntimeProbe.RequiredSharedFrameworkName,
"10.0.5"));
var hostDll = Path.Combine(_root, "LanMountainDesktop.AirAppHost.dll");
File.WriteAllText(hostDll, string.Empty);
var options = new DotNetRuntimeProbeOptions
{
Architecture = DotNetRuntimeArchitecture.X64,
ProgramFilesPath = programFiles,
ProgramFilesX86Path = Path.Combine(_root, "ProgramFilesX86"),
IncludeRegistry = false,
IncludeDotNetCli = false
};
var startInfo = AirAppProcessStarter.CreateStartInfo(hostDll, options);
Assert.Equal(dotnetHost, startInfo.FileName);
Assert.Equal(hostDll, startInfo.ArgumentList.Single());
}
public void Dispose()
{
if (Directory.Exists(_root))
{
Directory.Delete(_root, recursive: true);
}
}
}

View File

@@ -0,0 +1,135 @@
using LanMountainDesktop.Launcher.Services;
using Xunit;
namespace LanMountainDesktop.Tests;
public sealed class DotNetRuntimeProbeTests : IDisposable
{
private readonly string _root;
private readonly string _programFiles;
private readonly string _programFilesX86;
public DotNetRuntimeProbeTests()
{
_root = Path.Combine(Path.GetTempPath(), "LanMountainDesktop.DotNetRuntimeProbeTests", Guid.NewGuid().ToString("N"));
_programFiles = Path.Combine(_root, "ProgramFiles");
_programFilesX86 = Path.Combine(_root, "ProgramFilesX86");
Directory.CreateDirectory(_programFiles);
Directory.CreateDirectory(_programFilesX86);
}
[Fact]
public void Probe_AcceptsTargetArchitectureRuntime_WhenDotnetHostIsMissing()
{
CreateRuntime(_programFiles, "10.0.5");
var result = DotNetRuntimeProbe.Probe(CreateOptions(DotNetRuntimeArchitecture.X64));
Assert.True(result.IsAvailable);
Assert.Null(result.DotNetHostPath);
Assert.Contains(result.DetectedRuntimes, runtime => runtime.Version == "10.0.5");
}
[Fact]
public void Probe_X64DoesNotAcceptX86OnlyRuntime()
{
CreateRuntime(_programFilesX86, "10.0.5");
var result = DotNetRuntimeProbe.Probe(CreateOptions(DotNetRuntimeArchitecture.X64));
Assert.False(result.IsAvailable);
}
[Fact]
public void Probe_X86DoesNotAcceptX64OnlyRuntime()
{
CreateRuntime(_programFiles, "10.0.5");
var result = DotNetRuntimeProbe.Probe(CreateOptions(DotNetRuntimeArchitecture.X86));
Assert.False(result.IsAvailable);
}
[Fact]
public void Probe_RejectsOlderMajorVersions()
{
CreateRuntime(_programFiles, "8.0.25");
CreateRuntime(_programFiles, "9.0.14");
var result = DotNetRuntimeProbe.Probe(CreateOptions(DotNetRuntimeArchitecture.X64));
Assert.False(result.IsAvailable);
}
[Fact]
public void ValidateDotNetRuntimePrerequisite_ReturnsStructuredFailure_WhenRuntimeIsMissing()
{
if (!OperatingSystem.IsWindows())
{
return;
}
var appDir = Path.Combine(_root, "app-1.0.0");
Directory.CreateDirectory(appDir);
var hostPath = Path.Combine(appDir, "LanMountainDesktop.exe");
File.WriteAllText(hostPath, string.Empty);
File.WriteAllText(Path.Combine(appDir, "LanMountainDesktop.runtimeconfig.json"), "{}");
var plan = new HostLaunchPlan(
hostPath,
_root,
appDir,
[],
new Dictionary<string, string>(),
new() { Version = "1.0.0", Codename = "Test" });
var resolution = new HostResolutionResult
{
Success = true,
ResolvedHostPath = hostPath,
AppRoot = _root,
ResolutionSource = "test",
SearchedPaths = [hostPath]
};
var result = LauncherFlowCoordinator.ValidateDotNetRuntimePrerequisite(
plan,
resolution,
CreateOptions(DotNetRuntimeArchitecture.X64));
Assert.NotNull(result);
Assert.False(result.Success);
Assert.Equal("dotnet_runtime_missing", result.Code);
Assert.Equal("False", result.Details["dotnetRuntimeAvailable"]);
}
private DotNetRuntimeProbeOptions CreateOptions(DotNetRuntimeArchitecture architecture)
{
return new DotNetRuntimeProbeOptions
{
Architecture = architecture,
ProgramFilesPath = _programFiles,
ProgramFilesX86Path = _programFilesX86,
DotNetHostCandidates = [],
IncludeRegistry = false,
IncludeDotNetCli = false
};
}
private static void CreateRuntime(string programFilesRoot, string version)
{
Directory.CreateDirectory(Path.Combine(
programFilesRoot,
"dotnet",
"shared",
DotNetRuntimeProbe.RequiredSharedFrameworkName,
version));
}
public void Dispose()
{
if (Directory.Exists(_root))
{
Directory.Delete(_root, recursive: true);
}
}
}

View File

@@ -0,0 +1,57 @@
using Xunit;
namespace LanMountainDesktop.Tests;
public sealed class PackagingRuntimePolicyTests
{
[Fact]
public void WindowsPackageScript_PublishesLauncherRootAndFrameworkDependentAppDirectory()
{
var script = ReadRepositoryFile("LanMountainDesktop", "scripts", "package.ps1");
Assert.Contains("Publish-LauncherPayload", script);
Assert.Contains("\"app-$Version\"", script);
Assert.Contains("Publish-MainAppFrameworkDependentPayload", script);
Assert.Contains("\"--self-contained\", \"false\"", script);
Assert.Contains("\"-p:SelfContained=false\"", script);
}
[Fact]
public void WindowsPayloadGuard_BlocksBundledDotNetRuntimeFiles()
{
var script = ReadRepositoryFile("LanMountainDesktop", "scripts", "Optimize-PublishPayload.ps1");
Assert.Contains("coreclr.dll", script);
Assert.Contains("hostfxr.dll", script);
Assert.Contains("hostpolicy.dll", script);
Assert.Contains("System.Private.CoreLib.dll", script);
}
[Fact]
public void Installer_DownloadsArchitectureSpecificDesktopRuntime()
{
var installer = ReadRepositoryFile("LanMountainDesktop", "installer", "LanMountainDesktop.iss");
Assert.Contains("https://aka.ms/dotnet/10.0/windowsdesktop-runtime-win-x64.exe", installer);
Assert.Contains("https://aka.ms/dotnet/10.0/windowsdesktop-runtime-win-x86.exe", installer);
Assert.Contains("/install /quiet /norestart", installer);
Assert.Contains("ExitCode <> 3010", installer);
Assert.DoesNotContain("IsSelfContainedBuild", installer);
}
private static string ReadRepositoryFile(params string[] pathParts)
{
var directory = new DirectoryInfo(AppContext.BaseDirectory);
while (directory is not null && !File.Exists(Path.Combine(directory.FullName, "LanMountainDesktop.slnx")))
{
directory = directory.Parent;
}
if (directory is null)
{
throw new DirectoryNotFoundException("Unable to locate repository root.");
}
return File.ReadAllText(Path.Combine([directory.FullName, .. pathParts]));
}
}