using System.Net;
using System.Net.Http.Json;
using Flaro.Api.Endpoints;
namespace Flaro.Api.Tests;
/// Mehrere Mediatheken nebeneinander — wie bei Plex und Jellyfin.
///
///
/// Zwei Filmbibliotheken sind keine doppelte Filmbibliothek. „Filme"
/// und „Dokumentationen" liegen in verschiedenen Ordnern, gehören in der
/// Seitenleiste getrennt und dürfen sich in keiner Liste vermischen. Dass
/// das Modell es kann, hiess bisher nicht, dass es geprüft war.
///
public class MultipleLibraryTests
{
private readonly List _ordner = [];
[TearDown]
public void Aufraeumen()
{
foreach (var o in _ordner)
{
try { Directory.Delete(o, recursive: true); } catch (IOException) { /* Kür */ }
}
_ordner.Clear();
}
/// Ein Ordner mit den genannten Dateien darin.
private string Bestand(params string[] dateien)
{
var wurzel = Directory.CreateDirectory(
Path.Combine(Path.GetTempPath(), "flaro-mehrere-" + Guid.CreateVersion7().ToString("N"))).FullName;
_ordner.Add(wurzel);
foreach (var relativ in dateien)
{
var voll = Path.Combine(wurzel, relativ);
Directory.CreateDirectory(Path.GetDirectoryName(voll)!);
File.WriteAllBytes(voll, new byte[2048]);
}
return wurzel;
}
private static async Task Anlegen(
HttpClient client, string name, string art, string pfad)
{
var antwort = await client.PostAsJsonAsync("/api/v1/libraries",
new CreateLibraryRequest(name, art, pfad));
antwort.EnsureSuccessStatusCode();
return (await antwort.Content.ReadFromJsonAsync())!;
}
private static async Task Scannen(HttpClient client, Guid bibliothek)
{
(await client.PostAsync($"/api/v1/libraries/{bibliothek}/scan", null)).EnsureSuccessStatusCode();
for (var versuch = 0; versuch < 100; versuch++)
{
var stand = await client.GetFromJsonAsync($"/api/v1/libraries/{bibliothek}/scan");
if (stand!.State is "finished") return;
if (stand.State is "failed") Assert.Fail($"Der Scan ist gescheitert: {stand.Error}");
await Task.Delay(50);
}
Assert.Fail("Der Scan wurde in fünf Sekunden nicht fertig.");
}
[Test]
public async Task Zwei_Filmbibliotheken_bleiben_getrennt()
{
var spielfilme = Bestand("Matrix (1999)/Matrix (1999).mkv", "Inception (2010)/Inception (2010).mkv");
var dokus = Bestand("Winged Migration (2001)/Winged Migration (2001).mkv");
using var server = new FlaroServer();
var client = server.AlsAngemeldeter((await server.SetUpAndSignIn()).Token);
var a = await Anlegen(client, "Filme", "Movies", spielfilme);
var b = await Anlegen(client, "Dokumentationen", "Movies", dokus);
await Scannen(client, a.Id);
await Scannen(client, b.Id);
var inA = await client.GetFromJsonAsync>($"/api/v1/movies?library={a.Id}");
var inB = await client.GetFromJsonAsync>($"/api/v1/movies?library={b.Id}");
var alle = await client.GetFromJsonAsync>("/api/v1/movies");
Assert.Multiple(() =>
{
Assert.That(inA!.Total, Is.EqualTo(2));
Assert.That(inB!.Total, Is.EqualTo(1));
Assert.That(inB.Items[0].Title, Is.EqualTo("Winged Migration"));
// Ohne Einschränkung alle zusammen — für die Suche quer durch alles.
Assert.That(alle!.Total, Is.EqualTo(3));
});
}
/// Die Seitenleiste braucht zu jeder Zeile eine Zahl.
[Test]
public async Task Die_Liste_nennt_je_Bibliothek_die_Anzahl()
{
var filme = Bestand("Matrix (1999)/Matrix (1999).mkv");
var serien = Bestand("Dark/Season 01/Dark - S01E01 - Geheimnisse.mkv",
"Dark/Season 01/Dark - S01E02 - Luegen.mkv");
var leer = Bestand();
using var server = new FlaroServer();
var client = server.AlsAngemeldeter((await server.SetUpAndSignIn()).Token);
var a = await Anlegen(client, "Filme", "Movies", filme);
var b = await Anlegen(client, "Serien", "Shows", serien);
await Anlegen(client, "Noch nichts drin", "Movies", leer);
await Scannen(client, a.Id);
await Scannen(client, b.Id);
var liste = await client.GetFromJsonAsync>("/api/v1/libraries");
var nachNamen = liste!.ToDictionary(l => l.Name);
Assert.Multiple(() =>
{
Assert.That(nachNamen["Filme"].ItemCount, Is.EqualTo(1));
// **Serien, nicht Folgen.** Zwei Folgen einer Serie sind eine Zeile.
Assert.That(nachNamen["Serien"].ItemCount, Is.EqualTo(1));
Assert.That(nachNamen["Noch nichts drin"].ItemCount, Is.Zero);
});
}
[Test]
public async Task Eine_Bibliothek_laesst_sich_umbenennen()
{
using var server = new FlaroServer();
var client = server.AlsAngemeldeter((await server.SetUpAndSignIn()).Token);
var angelegt = await Anlegen(client, "Flime", "Movies", Bestand());
var antwort = await client.PutAsJsonAsync($"/api/v1/libraries/{angelegt.Id}",
new RenameLibraryRequest("Filme"));
var geaendert = await antwort.Content.ReadFromJsonAsync();
Assert.Multiple(() =>
{
Assert.That(geaendert!.Name, Is.EqualTo("Filme"));
Assert.That(geaendert.Path, Is.EqualTo(angelegt.Path), "der Pfad bleibt, wo er war");
});
}
[Test]
public async Task Ein_leerer_Name_wird_abgelehnt()
{
using var server = new FlaroServer();
var client = server.AlsAngemeldeter((await server.SetUpAndSignIn()).Token);
var angelegt = await Anlegen(client, "Filme", "Movies", Bestand());
var antwort = await client.PutAsJsonAsync($"/api/v1/libraries/{angelegt.Id}",
new RenameLibraryRequest(" "));
Assert.That(antwort.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}
/// Entfernt wird der Eintrag — nicht der Film auf der Platte.
///
///
/// Das ist die wichtigste Zusage dieses Servers. Ein Server, der
/// beim Aufräumen in der Oberfläche fremde Mediendateien löscht, ist
/// einer, den man nicht noch einmal benutzt.
///
[Test]
public async Task Loeschen_nimmt_die_Eintraege_und_laesst_die_Dateien_liegen()
{
var ordner = Bestand("Matrix (1999)/Matrix (1999).mkv");
var datei = Path.Combine(ordner, "Matrix (1999)", "Matrix (1999).mkv");
using var server = new FlaroServer();
var client = server.AlsAngemeldeter((await server.SetUpAndSignIn()).Token);
var angelegt = await Anlegen(client, "Filme", "Movies", ordner);
await Scannen(client, angelegt.Id);
Assert.That((await client.GetFromJsonAsync>("/api/v1/movies"))!.Total,
Is.EqualTo(1), "vorher ist er da");
var geloescht = await client.DeleteAsync($"/api/v1/libraries/{angelegt.Id}");
Assert.Multiple(() =>
{
Assert.That(geloescht.StatusCode, Is.EqualTo(HttpStatusCode.NoContent));
Assert.That(File.Exists(datei), Is.True, "die Datei liegt noch da");
});
var danach = await client.GetFromJsonAsync>("/api/v1/movies");
var liste = await client.GetFromJsonAsync>("/api/v1/libraries");
Assert.Multiple(() =>
{
Assert.That(danach!.Total, Is.Zero);
Assert.That(liste, Is.Empty);
});
}
[Test]
public async Task Nur_Administratoren_duerfen_loeschen_und_umbenennen()
{
using var server = new FlaroServer();
var admin = server.AlsAngemeldeter((await server.SetUpAndSignIn()).Token);
var angelegt = await Anlegen(admin, "Filme", "Movies", Bestand());
(await admin.PostAsJsonAsync("/api/v1/users",
new CreateUserRequest("mitbewohner", "ein-langes-passwort", false))).EnsureSuccessStatusCode();
var gast = server.AlsAngemeldeter(
(await server.SignIn("mitbewohner", "ein-langes-passwort", "iPad", "geraet-2")).Token);
var umbenannt = await gast.PutAsJsonAsync($"/api/v1/libraries/{angelegt.Id}",
new RenameLibraryRequest("Meins jetzt"));
var geloescht = await gast.DeleteAsync($"/api/v1/libraries/{angelegt.Id}");
Assert.Multiple(() =>
{
Assert.That(umbenannt.StatusCode, Is.EqualTo(HttpStatusCode.Forbidden));
Assert.That(geloescht.StatusCode, Is.EqualTo(HttpStatusCode.Forbidden));
});
}
/// „Zuletzt hinzugefügt" braucht eine andere Reihenfolge als A–Z.
[Test]
public async Task Nach_Aufnahme_sortiert_steht_das_Neueste_oben()
{
var ordner = Bestand("Zzz Zuletzt (2024)/Zzz Zuletzt (2024).mkv");
using var server = new FlaroServer();
var client = server.AlsAngemeldeter((await server.SetUpAndSignIn()).Token);
var angelegt = await Anlegen(client, "Filme", "Movies", ordner);
await Scannen(client, angelegt.Id);
// Ein zweiter Film, nachweislich später aufgenommen.
var voll = Path.Combine(ordner, "Aaa Zuerst (1999)", "Aaa Zuerst (1999).mkv");
Directory.CreateDirectory(Path.GetDirectoryName(voll)!);
await File.WriteAllBytesAsync(voll, new byte[2048]);
await Task.Delay(1100);
await Scannen(client, angelegt.Id);
var alphabetisch = await client.GetFromJsonAsync>("/api/v1/movies");
var nachAufnahme = await client.GetFromJsonAsync>("/api/v1/movies?sort=added");
Assert.Multiple(() =>
{
Assert.That(alphabetisch!.Items.Select(m => m.Title),
Is.EqualTo(new[] { "Aaa Zuerst", "Zzz Zuletzt" }));
Assert.That(nachAufnahme!.Items[0].Title, Is.EqualTo("Aaa Zuerst"),
"zuletzt gefunden steht oben");
});
}
}