using System.Net;
using System.Net.Http.Json;
using Flaro.Api.Endpoints;
namespace Flaro.Api.Tests;
/// Wer gerade was schaut.
public class DashboardTests
{
private string _bestand = "";
[SetUp]
public void Anlegen() => _bestand = Directory.CreateDirectory(
Path.Combine(Path.GetTempPath(), "flaro-dash-" + Guid.CreateVersion7().ToString("N"))).FullName;
[TearDown]
public void Aufraeumen()
{
try { Directory.Delete(_bestand, recursive: true); } catch (IOException) { /* Kür */ }
}
private void Datei(string relativ)
{
var voll = Path.Combine(_bestand, relativ);
Directory.CreateDirectory(Path.GetDirectoryName(voll)!);
File.WriteAllBytes(voll, new byte[2048]);
}
private async Task Eingelesen(FlaroServer server, string art = "Movies")
{
var admin = await server.SetUpAndSignIn();
var client = server.AlsAngemeldeter(admin.Token);
var angelegt = await client.PostAsJsonAsync("/api/v1/libraries",
new CreateLibraryRequest("Prüfbestand", art, _bestand));
angelegt.EnsureSuccessStatusCode();
var bibliothek = (await angelegt.Content.ReadFromJsonAsync())!;
(await client.PostAsync($"/api/v1/libraries/{bibliothek.Id}/scan", null)).EnsureSuccessStatusCode();
for (var versuch = 0; versuch < 100; versuch++)
{
var stand = await client.GetFromJsonAsync($"/api/v1/libraries/{bibliothek.Id}/scan");
if (stand!.State is "finished") return client;
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.");
return null!;
}
private static async Task ErsterFilm(HttpClient client) =>
(await client.GetFromJsonAsync>("/api/v1/movies"))!.Items[0].Id;
/// Die Fortschrittsmeldung ist zugleich das Lebenszeichen.
///
///
/// Kein zweites Verfahren, das ein Client vergessen könnte: er meldet
/// beim Abspielen ohnehin alle paar Sekunden, wo er steht.
///
[Test]
public async Task Eine_Fortschrittsmeldung_erscheint_im_Dashboard()
{
Datei("Matrix (1999)/Matrix (1999).mkv");
using var server = new FlaroServer();
var client = await Eingelesen(server);
var film = await ErsterFilm(client);
await client.PostAsJsonAsync($"/api/v1/items/{film}/progress",
new ProgressRequest(600, 7200));
var laufend = await client.GetFromJsonAsync>("/api/v1/system/sessions");
Assert.Multiple(() =>
{
Assert.That(laufend, Has.Count.EqualTo(1));
Assert.That(laufend![0].Title, Is.EqualTo("Matrix"));
Assert.That(laufend[0].UserName, Is.EqualTo("guido"));
Assert.That(laufend[0].DeviceName, Is.EqualTo("iPhone"));
Assert.That(laufend[0].PositionSeconds, Is.EqualTo(600));
});
}
/// Beendet heisst sofort weg, nicht erst nach einer Minute.
///
///
/// Ohne das stünde ein beendeter Film noch eine Minute als „läuft" — und
/// wer gerade den Spieler geschlossen hat, sähe sich selbst beim Schauen
/// zu.
///
[Test]
public async Task Eine_beendete_Wiedergabe_verschwindet_sofort()
{
Datei("Matrix (1999)/Matrix (1999).mkv");
using var server = new FlaroServer();
var client = await Eingelesen(server);
var film = await ErsterFilm(client);
await client.PostAsJsonAsync($"/api/v1/items/{film}/progress", new ProgressRequest(600, 7200));
await client.PostAsJsonAsync($"/api/v1/items/{film}/progress",
new ProgressRequest(900, 7200, Stopped: true));
var laufend = await client.GetFromJsonAsync>("/api/v1/system/sessions");
Assert.That(laufend, Is.Empty);
// Der Fortschritt bleibt trotzdem erhalten — nur das „läuft gerade"
// ist vorbei.
var seite = await client.GetFromJsonAsync>("/api/v1/movies");
Assert.That(seite!.Items[0].State!.PositionSeconds, Is.EqualTo(900));
}
/// Eine Folge nennt Serie und Nummer, nicht nur den Folgentitel.
[Test]
public async Task Eine_Folge_erscheint_mit_Serie_und_Nummer()
{
Datei("Dark/Season 01/Dark - S01E02 - Luegen.mkv");
using var server = new FlaroServer();
var client = await Eingelesen(server, "Shows");
var serien = await client.GetFromJsonAsync>("/api/v1/series");
var folgen = await client.GetFromJsonAsync>(
$"/api/v1/series/{serien!.Items[0].Id}/episodes");
await client.PostAsJsonAsync($"/api/v1/items/{folgen!.Items[0].Id}/progress",
new ProgressRequest(400, 2700));
var laufend = await client.GetFromJsonAsync>("/api/v1/system/sessions");
Assert.Multiple(() =>
{
Assert.That(laufend![0].Title, Is.EqualTo("Dark"));
Assert.That(laufend[0].SubTitle, Does.Contain("S1").And.Contain("F2"));
});
}
/// Wer wann was schaut, geht nicht jeden an.
[Test]
public async Task Nur_Administratoren_sehen_das_Dashboard()
{
using var server = new FlaroServer();
var admin = server.AlsAngemeldeter((await server.SetUpAndSignIn()).Token);
(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);
Assert.Multiple(async () =>
{
Assert.That((await gast.GetAsync("/api/v1/system/sessions")).StatusCode,
Is.EqualTo(HttpStatusCode.Forbidden));
Assert.That((await gast.GetAsync("/api/v1/system/status")).StatusCode,
Is.EqualTo(HttpStatusCode.Forbidden));
});
}
/// Zwei Geräte desselben Menschen sind zwei Wiedergaben.
///
///
/// Derselbe Mensch kann auf dem Fernseher und auf dem Telefon
/// gleichzeitig etwas laufen lassen; beides gehört ins Dashboard.
///
[Test]
public async Task Zwei_Geraete_erscheinen_getrennt()
{
Datei("Matrix (1999)/Matrix (1999).mkv");
using var server = new FlaroServer();
var telefon = await Eingelesen(server);
var film = await ErsterFilm(telefon);
var fernseher = server.AlsAngemeldeter(
(await server.SignIn("guido", "ein-langes-passwort", "Apple TV", "geraet-tv")).Token);
await telefon.PostAsJsonAsync($"/api/v1/items/{film}/progress", new ProgressRequest(100, 7200));
await fernseher.PostAsJsonAsync($"/api/v1/items/{film}/progress", new ProgressRequest(3000, 7200));
var laufend = await telefon.GetFromJsonAsync>("/api/v1/system/sessions");
Assert.Multiple(() =>
{
Assert.That(laufend, Has.Count.EqualTo(2));
Assert.That(laufend!.Select(w => w.DeviceName),
Is.EquivalentTo(new[] { "iPhone", "Apple TV" }));
});
}
[Test]
public async Task Der_Serverzustand_zaehlt_was_gerade_laeuft()
{
Datei("Matrix (1999)/Matrix (1999).mkv");
using var server = new FlaroServer();
var client = await Eingelesen(server);
var film = await ErsterFilm(client);
await client.PostAsJsonAsync($"/api/v1/items/{film}/progress", new ProgressRequest(60, 7200));
var stand = await client.GetFromJsonAsync("/api/v1/system/status");
Assert.Multiple(() =>
{
Assert.That(stand!.Playing, Is.EqualTo(1));
Assert.That(stand.Scanning, Is.Zero, "der Scan ist längst durch");
Assert.That(stand.Uptime, Is.GreaterThan(0));
});
}
}