Untis-API Optimierung.

This commit is contained in:
2026-08-24 22:33:30 +02:00
parent 1db16f8b69
commit 17475a781f
9 changed files with 109 additions and 53 deletions
@@ -1,4 +1,5 @@
using System.Net;
using System.Diagnostics;
using System.Text;
using LehrerApp.WebUntis;
using Xunit;
@@ -84,6 +85,20 @@ public sealed class WebUntisClientTests
await client.DisposeAsync();
}
[Fact]
public async Task Dispose_BegrenztEinenNichtAntwortendenLogout()
{
var handler = new HangingLogoutHandler();
var client = CreateClient(handler);
await client.GetSchoolYearsAsync(CancellationToken.None);
var elapsed = Stopwatch.StartNew();
await client.DisposeAsync();
Assert.True(elapsed.Elapsed < TimeSpan.FromSeconds(5));
Assert.True(handler.LogoutWasCancelled);
}
[Fact]
public async Task VollstaendigeLoginUrl_TrenntRegionalenServerUndSchulkennung()
{
@@ -128,7 +143,7 @@ public sealed class WebUntisClientTests
}
[Fact]
public async Task FehlzeitenUndKlassenbuch_WerdenNachSchuelerAbgerufenUndTypisiert()
public async Task FehlzeitenUndKlassenbuch_WerdenTypisiertAbgerufen()
{
var handler = new QueueHandler(
Json("{\"result\":{\"sessionId\":\"s\"}}"),
@@ -147,15 +162,15 @@ public sealed class WebUntisClientTests
Json("{\"result\":{}}"));
var client = CreateClient(handler);
var report = await client.GetStudentAbsencesAsync(9001, 20260801, 20270731,
CancellationToken.None);
var absences = await client.GetAbsencesAsync(20260801, 20270731, CancellationToken.None);
var entries = await client.GetClassRegisterEntriesAsync(17, 20260801, 20270731,
CancellationToken.None);
var categories = await client.GetClassRegisterCategoriesAsync(CancellationToken.None);
var groups = await client.GetClassRegisterCategoryGroupsAsync(CancellationToken.None);
var absence = Assert.Single(report.Absences);
Assert.Equal(45, report.AbsentMinutes);
Assert.Equal(2, absences.Count);
var absence = Assert.Single(absences, x => x.StudentKey == 9001);
Assert.Equal(45, absence.AbsentMinutes);
Assert.Equal("entschuldigt", absence.ExcuseStatus);
Assert.Equal(7, Assert.Single(absence.TeacherIds));
var entry = Assert.Single(entries);
@@ -207,5 +222,33 @@ public sealed class WebUntisClientTests
}
}
private sealed class HangingLogoutHandler : HttpMessageHandler
{
public bool LogoutWasCancelled { get; private set; }
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
var body = request.Content is null
? ""
: await request.Content.ReadAsStringAsync(cancellationToken);
if (body.Contains("\"method\":\"authenticate\""))
return Json("{\"result\":{\"sessionId\":\"s\"}}");
if (body.Contains("\"method\":\"getSchoolyears\""))
return Json("{\"result\":[]}");
try
{
await Task.Delay(Timeout.InfiniteTimeSpan, cancellationToken);
throw new InvalidOperationException("Der simulierte Logout darf nicht regulär enden.");
}
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
{
LogoutWasCancelled = true;
throw;
}
}
}
private sealed record CapturedRequest(string Uri, string Body, string Cookie);
}
@@ -37,6 +37,20 @@ public sealed class WebUntisStudentReportParserTests
Assert.Equal("MUS\"T", student.DisplayName);
}
[Fact]
public void Parse_AkzeptiertIsoDatumswerteOhneTrennzeichen()
{
const string report = "id\texternKey\tklasse.name\tbirthDate\tentryDate\texitDate\r\n" +
"17\t9001\t10a\t20100203\t20210801\t20270731\r\n";
var student = Assert.Single(WebUntisStudentReportParser.Parse(report));
Assert.Equal(20100203, student.BirthDate);
Assert.Equal("20100203", student.BirthDateRaw);
Assert.Equal(20210801, student.EntryDate);
Assert.Equal(20270731, student.ExitDate);
}
[Fact]
public void Parse_LehntUngueltigePflichtIdAb()
{