mirror of
https://github.com/moeacgx/Telegram-Panel.git
synced 2026-09-03 07:17:51 +08:00
385 lines
14 KiB
C#
385 lines
14 KiB
C#
using System.Diagnostics;
|
|
using Xunit;
|
|
|
|
namespace TelegramPanel.Web.Tests;
|
|
|
|
public sealed class EntrypointScriptTests
|
|
{
|
|
[Fact]
|
|
public void Entrypoint_RollsBackAttemptedUnconfirmedVersion()
|
|
{
|
|
if (!OperatingSystem.IsLinux())
|
|
return;
|
|
|
|
var root = CreateTempDirectory();
|
|
try
|
|
{
|
|
var data = Path.Combine(root, "data");
|
|
var imageApp = Path.Combine(root, "app");
|
|
var current = Path.Combine(data, "app-current");
|
|
var previous = Path.Combine(data, "app-previous");
|
|
Directory.CreateDirectory(imageApp);
|
|
CreateRunnableVersion(current, "bad");
|
|
CreateRunnableVersion(previous, "good");
|
|
File.WriteAllText(Path.Combine(current, ".telegram-panel-update-attempted"), "{}");
|
|
|
|
var resultPath = Path.Combine(root, "started-from.txt");
|
|
RunEntrypoint(data, imageApp, resultPath);
|
|
|
|
Assert.Equal(Path.GetFullPath(current), File.ReadAllText(resultPath).Trim());
|
|
Assert.Equal("good", File.ReadAllText(Path.Combine(current, "version.txt")));
|
|
Assert.False(Directory.Exists(previous));
|
|
|
|
var failed = Assert.Single(Directory.GetDirectories(data, "app-failed-*"));
|
|
Assert.Equal("bad", File.ReadAllText(Path.Combine(failed, "version.txt")));
|
|
}
|
|
finally
|
|
{
|
|
TryDeleteDirectory(root);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Entrypoint_MarksPendingVersionAttemptedBeforeLaunching()
|
|
{
|
|
if (!OperatingSystem.IsLinux())
|
|
return;
|
|
|
|
var root = CreateTempDirectory();
|
|
try
|
|
{
|
|
var data = Path.Combine(root, "data");
|
|
var imageApp = Path.Combine(root, "app");
|
|
var current = Path.Combine(data, "app-current");
|
|
Directory.CreateDirectory(imageApp);
|
|
CreateRunnableVersion(current, "new");
|
|
File.WriteAllText(Path.Combine(current, ".telegram-panel-update-pending"), "{}");
|
|
|
|
var resultPath = Path.Combine(root, "started-from.txt");
|
|
RunEntrypoint(data, imageApp, resultPath);
|
|
|
|
Assert.Equal(Path.GetFullPath(current), File.ReadAllText(resultPath).Trim());
|
|
Assert.False(File.Exists(Path.Combine(current, ".telegram-panel-update-pending")));
|
|
Assert.True(File.Exists(Path.Combine(current, ".telegram-panel-update-attempted")));
|
|
}
|
|
finally
|
|
{
|
|
TryDeleteDirectory(root);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Entrypoint_FallsBackToImageVersionWhenNoBackupExists()
|
|
{
|
|
if (!OperatingSystem.IsLinux())
|
|
return;
|
|
|
|
var root = CreateTempDirectory();
|
|
try
|
|
{
|
|
var data = Path.Combine(root, "data");
|
|
var imageApp = Path.Combine(root, "app");
|
|
var current = Path.Combine(data, "app-current");
|
|
CreateRunnableVersion(imageApp, "image");
|
|
CreateRunnableVersion(current, "bad");
|
|
File.WriteAllText(Path.Combine(current, ".telegram-panel-update-attempted"), "{}");
|
|
|
|
var resultPath = Path.Combine(root, "started-from.txt");
|
|
RunEntrypoint(data, imageApp, resultPath);
|
|
|
|
Assert.Equal(Path.GetFullPath(imageApp), File.ReadAllText(resultPath).Trim());
|
|
Assert.False(Directory.Exists(current));
|
|
var failed = Assert.Single(Directory.GetDirectories(data, "app-failed-*"));
|
|
Assert.Equal("bad", File.ReadAllText(Path.Combine(failed, "version.txt")));
|
|
}
|
|
finally
|
|
{
|
|
TryDeleteDirectory(root);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Entrypoint_MigratesLegacyMarkerForPackageWithNewEntrypoint()
|
|
{
|
|
if (!OperatingSystem.IsLinux())
|
|
return;
|
|
|
|
var root = CreateTempDirectory();
|
|
try
|
|
{
|
|
var data = Path.Combine(root, "data");
|
|
var imageApp = Path.Combine(root, "app");
|
|
var current = Path.Combine(data, "app-current");
|
|
Directory.CreateDirectory(imageApp);
|
|
CreateRunnableVersion(current, "new");
|
|
File.WriteAllText(Path.Combine(current, ".telegram-panel-self-update"), "{}");
|
|
var packagedEntrypoint = Path.Combine(current, "self-update", "entrypoint.sh");
|
|
Directory.CreateDirectory(Path.GetDirectoryName(packagedEntrypoint)!);
|
|
File.WriteAllText(packagedEntrypoint, "#!/usr/bin/env sh\n");
|
|
|
|
var resultPath = Path.Combine(root, "started-from.txt");
|
|
RunEntrypoint(data, imageApp, resultPath);
|
|
|
|
Assert.Equal(Path.GetFullPath(current), File.ReadAllText(resultPath).Trim());
|
|
Assert.True(File.Exists(Path.Combine(current, ".telegram-panel-update-attempted")));
|
|
}
|
|
finally
|
|
{
|
|
TryDeleteDirectory(root);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Entrypoint_PrefersNewerImageOverConfirmedOlderSelfUpdate()
|
|
{
|
|
if (!OperatingSystem.IsLinux())
|
|
return;
|
|
|
|
var root = CreateTempDirectory();
|
|
try
|
|
{
|
|
var data = Path.Combine(root, "data");
|
|
var imageApp = Path.Combine(root, "app");
|
|
var current = Path.Combine(data, "app-current");
|
|
Directory.CreateDirectory(imageApp);
|
|
CreateRunnableVersion(imageApp, "1.31.38");
|
|
File.WriteAllText(
|
|
Path.Combine(imageApp, "version.txt"),
|
|
"1.31.38",
|
|
new System.Text.UTF8Encoding(encoderShouldEmitUTF8Identifier: true));
|
|
CreateRunnableVersion(current, "1.31.37");
|
|
File.WriteAllText(Path.Combine(current, ".telegram-panel-update-confirmed"), "{}");
|
|
|
|
var resultPath = Path.Combine(root, "started-from.txt");
|
|
RunEntrypoint(data, imageApp, resultPath);
|
|
|
|
Assert.Equal(Path.GetFullPath(imageApp), File.ReadAllText(resultPath).Trim());
|
|
Assert.False(Directory.Exists(current));
|
|
var obsolete = Assert.Single(Directory.GetDirectories(data, "app-obsolete-*"));
|
|
Assert.Equal("1.31.37", File.ReadAllText(Path.Combine(obsolete, "version.txt")));
|
|
}
|
|
finally
|
|
{
|
|
TryDeleteDirectory(root);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Entrypoint_PrefersNewerImageOverLegacyOlderSelfUpdate()
|
|
{
|
|
if (!OperatingSystem.IsLinux())
|
|
return;
|
|
|
|
var root = CreateTempDirectory();
|
|
try
|
|
{
|
|
var data = Path.Combine(root, "data");
|
|
var imageApp = Path.Combine(root, "app");
|
|
var current = Path.Combine(data, "app-current");
|
|
CreateRunnableVersion(imageApp, "1.31.38");
|
|
CreateRunnableVersion(current, "1.31.37");
|
|
File.WriteAllText(Path.Combine(current, ".telegram-panel-self-update"), "{}");
|
|
|
|
var resultPath = Path.Combine(root, "started-from.txt");
|
|
RunEntrypoint(data, imageApp, resultPath);
|
|
|
|
Assert.Equal(Path.GetFullPath(imageApp), File.ReadAllText(resultPath).Trim());
|
|
Assert.False(Directory.Exists(current));
|
|
var obsolete = Assert.Single(Directory.GetDirectories(data, "app-obsolete-*"));
|
|
Assert.Equal("1.31.37", File.ReadAllText(Path.Combine(obsolete, "version.txt")));
|
|
}
|
|
finally
|
|
{
|
|
TryDeleteDirectory(root);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Entrypoint_PrefersVersionedImageWhenLegacySelfUpdateHasNoVersionFile()
|
|
{
|
|
if (!OperatingSystem.IsLinux())
|
|
return;
|
|
|
|
var root = CreateTempDirectory();
|
|
try
|
|
{
|
|
var data = Path.Combine(root, "data");
|
|
var imageApp = Path.Combine(root, "app");
|
|
var current = Path.Combine(data, "app-current");
|
|
CreateRunnableVersion(imageApp, "1.31.38");
|
|
CreateRunnableVersion(current, "1.31.37");
|
|
File.Delete(Path.Combine(current, "version.txt"));
|
|
File.WriteAllText(Path.Combine(current, ".telegram-panel-update-confirmed"), "{}");
|
|
|
|
var resultPath = Path.Combine(root, "started-from.txt");
|
|
RunEntrypoint(data, imageApp, resultPath);
|
|
|
|
Assert.Equal(Path.GetFullPath(imageApp), File.ReadAllText(resultPath).Trim());
|
|
Assert.False(Directory.Exists(current));
|
|
var obsolete = Assert.Single(Directory.GetDirectories(data, "app-obsolete-*"));
|
|
Assert.False(File.Exists(Path.Combine(obsolete, "version.txt")));
|
|
}
|
|
finally
|
|
{
|
|
TryDeleteDirectory(root);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Entrypoint_PrefersNewerConfirmedSelfUpdateOverOlderImage()
|
|
{
|
|
if (!OperatingSystem.IsLinux())
|
|
return;
|
|
|
|
var root = CreateTempDirectory();
|
|
try
|
|
{
|
|
var data = Path.Combine(root, "data");
|
|
var imageApp = Path.Combine(root, "app");
|
|
var current = Path.Combine(data, "app-current");
|
|
Directory.CreateDirectory(imageApp);
|
|
CreateRunnableVersion(imageApp, "1.31.37");
|
|
CreateRunnableVersion(current, "1.31.38");
|
|
File.WriteAllText(Path.Combine(current, ".telegram-panel-update-confirmed"), "{}");
|
|
|
|
var resultPath = Path.Combine(root, "started-from.txt");
|
|
RunEntrypoint(data, imageApp, resultPath);
|
|
|
|
Assert.Equal(Path.GetFullPath(current), File.ReadAllText(resultPath).Trim());
|
|
Assert.True(Directory.Exists(current));
|
|
Assert.Empty(Directory.GetDirectories(data, "app-obsolete-*"));
|
|
}
|
|
finally
|
|
{
|
|
TryDeleteDirectory(root);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Entrypoint_ImageModeAlwaysUsesImageDirectory()
|
|
{
|
|
if (!OperatingSystem.IsLinux())
|
|
return;
|
|
|
|
var root = CreateTempDirectory();
|
|
try
|
|
{
|
|
var data = Path.Combine(root, "data");
|
|
var imageApp = Path.Combine(root, "app");
|
|
var current = Path.Combine(data, "app-current");
|
|
CreateRunnableVersion(imageApp, "1.31.37");
|
|
CreateRunnableVersion(current, "1.31.38");
|
|
File.WriteAllText(Path.Combine(current, ".telegram-panel-update-confirmed"), "{}");
|
|
|
|
var resultPath = Path.Combine(root, "started-from.txt");
|
|
RunEntrypoint(data, imageApp, resultPath, "image");
|
|
|
|
Assert.Equal(Path.GetFullPath(imageApp), File.ReadAllText(resultPath).Trim());
|
|
Assert.True(Directory.Exists(current));
|
|
}
|
|
finally
|
|
{
|
|
TryDeleteDirectory(root);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Entrypoint_BinaryModeAlwaysUsesConfirmedBinaryDirectory()
|
|
{
|
|
if (!OperatingSystem.IsLinux())
|
|
return;
|
|
|
|
var root = CreateTempDirectory();
|
|
try
|
|
{
|
|
var data = Path.Combine(root, "data");
|
|
var imageApp = Path.Combine(root, "app");
|
|
var current = Path.Combine(data, "app-current");
|
|
CreateRunnableVersion(imageApp, "1.31.38");
|
|
CreateRunnableVersion(current, "1.31.37");
|
|
File.WriteAllText(Path.Combine(current, ".telegram-panel-update-confirmed"), "{}");
|
|
|
|
var resultPath = Path.Combine(root, "started-from.txt");
|
|
RunEntrypoint(data, imageApp, resultPath, "binary");
|
|
|
|
Assert.Equal(Path.GetFullPath(current), File.ReadAllText(resultPath).Trim());
|
|
}
|
|
finally
|
|
{
|
|
TryDeleteDirectory(root);
|
|
}
|
|
}
|
|
|
|
private static void RunEntrypoint(string data, string imageApp, string resultPath, string? updateMode = null)
|
|
{
|
|
var scriptPath = FindRepositoryFile(Path.Combine("docker", "entrypoint.sh"));
|
|
var startInfo = new ProcessStartInfo("/bin/sh")
|
|
{
|
|
UseShellExecute = false,
|
|
RedirectStandardOutput = true,
|
|
RedirectStandardError = true
|
|
};
|
|
startInfo.ArgumentList.Add(scriptPath);
|
|
startInfo.Environment["TELEGRAM_PANEL_DATA_DIR"] = data;
|
|
startInfo.Environment["TELEGRAM_PANEL_DEFAULT_APP_DIR"] = imageApp;
|
|
startInfo.Environment["TELEGRAM_PANEL_DOTNET_COMMAND"] = "/bin/sh";
|
|
startInfo.Environment["TELEGRAM_PANEL_TEST_RESULT"] = resultPath;
|
|
if (!string.IsNullOrWhiteSpace(updateMode))
|
|
startInfo.Environment["TELEGRAM_PANEL_UPDATE_MODE"] = updateMode;
|
|
|
|
using var process = Process.Start(startInfo)
|
|
?? throw new InvalidOperationException("无法启动入口脚本测试进程");
|
|
if (!process.WaitForExit(10_000))
|
|
{
|
|
process.Kill(entireProcessTree: true);
|
|
throw new TimeoutException("入口脚本测试超过 10 秒");
|
|
}
|
|
|
|
var standardError = process.StandardError.ReadToEnd();
|
|
Assert.True(process.ExitCode == 0, $"入口脚本退出码:{process.ExitCode}\n{standardError}");
|
|
}
|
|
|
|
private static void CreateRunnableVersion(string directory, string version)
|
|
{
|
|
Directory.CreateDirectory(directory);
|
|
File.WriteAllText(Path.Combine(directory, "version.txt"), version);
|
|
File.WriteAllText(
|
|
Path.Combine(directory, "TelegramPanel.Web.dll"),
|
|
"printf '%s' \"$PWD\" > \"$TELEGRAM_PANEL_TEST_RESULT\"\n");
|
|
}
|
|
|
|
private static string FindRepositoryFile(string relativePath)
|
|
{
|
|
for (var directory = new DirectoryInfo(AppContext.BaseDirectory);
|
|
directory != null;
|
|
directory = directory.Parent)
|
|
{
|
|
var candidate = Path.Combine(directory.FullName, relativePath);
|
|
if (File.Exists(candidate))
|
|
return candidate;
|
|
}
|
|
|
|
throw new FileNotFoundException($"未找到仓库文件:{relativePath}");
|
|
}
|
|
|
|
private static string CreateTempDirectory()
|
|
{
|
|
var path = Path.Combine(Path.GetTempPath(), "telegram-panel-entrypoint-tests", Guid.NewGuid().ToString("N"));
|
|
Directory.CreateDirectory(path);
|
|
return path;
|
|
}
|
|
|
|
private static void TryDeleteDirectory(string path)
|
|
{
|
|
try
|
|
{
|
|
if (Directory.Exists(path))
|
|
Directory.Delete(path, recursive: true);
|
|
}
|
|
catch
|
|
{
|
|
// 测试清理失败不应掩盖断言结果。
|
|
}
|
|
}
|
|
}
|