POST /api/publish: rendert SiteSnapshot->HTML in _staging_new/, atomic swap -> live/ (rename, ein Syscall). publicsite-nginx:alpine serviert live/ read-only auf Port 8081. Shared Volume api(rw)/publicsite(ro). Manager bleibt LAN-only. 5 neue Tests (atomic swap, UTF-8, mehrfach), 184/184 gruen. compose config OK. Vhost-Snippet + web-deploy.md (Deutsch) beigelegt; <DOMAIN> wartet auf Julian.
104 lines
3.6 KiB
C#
104 lines
3.6 KiB
C#
using GerbilManagerWebAPI.Endpoints;
|
|
|
|
namespace GerbilManager.Tests;
|
|
|
|
/// <summary>WEB-2: POST /api/publish — atomic swap, file layout, staging cleanup.</summary>
|
|
public class CmsPublishTests
|
|
{
|
|
private static string TempRoot() =>
|
|
Path.Combine(Path.GetTempPath(), "gm-publish-test-" + Guid.NewGuid().ToString("N"));
|
|
|
|
[Fact]
|
|
public async Task Publish_erstellt_live_Verzeichnis_mit_allen_Dateien()
|
|
{
|
|
var root = TempRoot();
|
|
try
|
|
{
|
|
var files = new Dictionary<string, string>
|
|
{
|
|
["index.html"] = "<html>start</html>",
|
|
["kontakt/index.html"] = "<html>kontakt</html>",
|
|
["assets/site.css"] = "body {}",
|
|
};
|
|
|
|
await CmsEndpoints.PublishToDirectoryAsync(files, root);
|
|
|
|
Assert.True(File.Exists(Path.Combine(root, "live", "index.html")));
|
|
Assert.True(File.Exists(Path.Combine(root, "live", "kontakt", "index.html")));
|
|
Assert.True(File.Exists(Path.Combine(root, "live", "assets", "site.css")));
|
|
Assert.Equal("<html>start</html>",
|
|
await File.ReadAllTextAsync(Path.Combine(root, "live", "index.html")));
|
|
}
|
|
finally { if (Directory.Exists(root)) Directory.Delete(root, true); }
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Publish_atomarer_Swap_ueberschreibt_alte_live_Version()
|
|
{
|
|
var root = TempRoot();
|
|
try
|
|
{
|
|
await CmsEndpoints.PublishToDirectoryAsync(
|
|
new Dictionary<string, string> { ["index.html"] = "version-1" }, root);
|
|
|
|
await CmsEndpoints.PublishToDirectoryAsync(
|
|
new Dictionary<string, string> { ["index.html"] = "version-2" }, root);
|
|
|
|
var content = await File.ReadAllTextAsync(Path.Combine(root, "live", "index.html"));
|
|
Assert.Equal("version-2", content);
|
|
}
|
|
finally { if (Directory.Exists(root)) Directory.Delete(root, true); }
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Publish_kein_staging_oder_old_Verzeichnis_nach_Swap()
|
|
{
|
|
var root = TempRoot();
|
|
try
|
|
{
|
|
await CmsEndpoints.PublishToDirectoryAsync(
|
|
new Dictionary<string, string> { ["index.html"] = "x" }, root);
|
|
|
|
Assert.False(Directory.Exists(Path.Combine(root, "_staging_new")));
|
|
Assert.False(Directory.Exists(Path.Combine(root, "_old")));
|
|
}
|
|
finally { if (Directory.Exists(root)) Directory.Delete(root, true); }
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Publish_mehrfach_ohne_Fehler()
|
|
{
|
|
var root = TempRoot();
|
|
try
|
|
{
|
|
for (int i = 1; i <= 3; i++)
|
|
{
|
|
await CmsEndpoints.PublishToDirectoryAsync(
|
|
new Dictionary<string, string> { ["index.html"] = $"v{i}" }, root);
|
|
}
|
|
|
|
Assert.Equal("v3",
|
|
await File.ReadAllTextAsync(Path.Combine(root, "live", "index.html")));
|
|
}
|
|
finally { if (Directory.Exists(root)) Directory.Delete(root, true); }
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Publish_UTF8_Inhalt_korrekt_gespeichert()
|
|
{
|
|
var root = TempRoot();
|
|
try
|
|
{
|
|
const string german = "<html>Züchter — Rennmäuse & mehr</html>";
|
|
await CmsEndpoints.PublishToDirectoryAsync(
|
|
new Dictionary<string, string> { ["index.html"] = german }, root);
|
|
|
|
var content = await File.ReadAllTextAsync(
|
|
Path.Combine(root, "live", "index.html"),
|
|
System.Text.Encoding.UTF8);
|
|
Assert.Equal(german, content);
|
|
}
|
|
finally { if (Directory.Exists(root)) Directory.Delete(root, true); }
|
|
}
|
|
}
|