Files
LehrerApp/LehrerApp.Sync.Tests/EventQueueTests.cs
adminandClaude Sonnet 5 979511ab6a fix: Kontowechsel ließ Push dauerhaft mit 404 scheitern
Nach einem Login mit korrigierter Groß-/Kleinschreibung (siehe vorheriger Fix zur userId-
Stabilität) bezog sich die lokale Versionsverfolgung je Entität (BasedOnServerSeq-Cache) und der
Pull-Cursor weiterhin auf das alte Konto - ServerSeq-Werte sind aber nur innerhalb des Event-Logs
EINES Kontos gültig. Der Push wurde zu Recht abgelehnt, der Server kannte die Entität unter der
neuen userId aber gar nicht (404 beim Nachladen), und HandleRejectedAsync gab bei einem 404
bisher einfach auf, ohne den veralteten Cache-Eintrag zu bereinigen - derselbe Fehlschlag bei
jedem weiteren Sync-Versuch.

Dreiteiliger Fix: (1) ein 404 beim Nachladen löscht jetzt den stale Cache-Eintrag, sodass der
nächste Push die Entität korrekt als neu behandelt und selbstheilend durchgeht; (2) der
"Vollständigen Sync erzwingen"-Button setzt jetzt auch die Push-Versionsverfolgung zurück, nicht
nur den Pull-Cursor; (3) SyncLogin erkennt einen echten Kontowechsel künftig proaktiv anhand der
kanonischen userId aus der Server-Antwort und resettet automatisch, bevor der Folgefehler
überhaupt auftreten kann.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-19 00:05:24 +02:00

149 lines
4.6 KiB
C#

using LehrerApp.Sync.Models;
using Xunit;
namespace LehrerApp.Sync.Tests;
public sealed class EventQueueTests
{
[Fact]
public void MarkReviewed_EntferntKonfliktAusDerUnreviewedListe()
{
using var temp = new TempEventQueue();
var conflict = new ConflictEntry
{
LocalEvent = MakeEvent(),
RemoteEvent = MakeEvent(),
Resolution = "LocalWon",
};
temp.Queue.AddConflict(conflict);
temp.Queue.MarkReviewed(conflict.Id);
Assert.Empty(temp.Queue.GetUnreviewed());
Assert.Equal(0, temp.Queue.ConflictCount());
}
[Fact]
public void MarkReviewed_UnbekannteId_TutNichtsUndWirftNicht()
{
using var temp = new TempEventQueue();
var exception = Record.Exception(() => temp.Queue.MarkReviewed(Guid.NewGuid()));
Assert.Null(exception);
}
[Fact]
public void GetKnownServerSeq_UnbekannteEntitaet_LiefertNull()
{
using var temp = new TempEventQueue();
Assert.Null(temp.Queue.GetKnownServerSeq("Lesson", Guid.NewGuid().ToString()));
}
[Fact]
public void SetKnownServerSeq_GefolgtVonGet_LiefertDenGesetztenWert()
{
using var temp = new TempEventQueue();
var entityId = Guid.NewGuid().ToString();
temp.Queue.SetKnownServerSeq("Lesson", entityId, 42);
Assert.Equal(42, temp.Queue.GetKnownServerSeq("Lesson", entityId));
}
[Fact]
public void SetKnownServerSeq_ErneutesSetzen_UeberschreibtDenAltenWert()
{
using var temp = new TempEventQueue();
var entityId = Guid.NewGuid().ToString();
temp.Queue.SetKnownServerSeq("Lesson", entityId, 42);
temp.Queue.SetKnownServerSeq("Lesson", entityId, 43);
Assert.Equal(43, temp.Queue.GetKnownServerSeq("Lesson", entityId));
}
[Fact]
public void SetKnownServerSeq_GleicheEntityIdAndererEntityType_BleibtGetrennt()
{
using var temp = new TempEventQueue();
var entityId = Guid.NewGuid().ToString();
temp.Queue.SetKnownServerSeq("Lesson", entityId, 42);
temp.Queue.SetKnownServerSeq("Unit", entityId, 7);
Assert.Equal(42, temp.Queue.GetKnownServerSeq("Lesson", entityId));
Assert.Equal(7, temp.Queue.GetKnownServerSeq("Unit", entityId));
}
[Fact]
public void ClearKnownServerSeq_EntferntNurDieAngegebeneEntitaet()
{
using var temp = new TempEventQueue();
var entityId = Guid.NewGuid().ToString();
temp.Queue.SetKnownServerSeq("Lesson", entityId, 42);
temp.Queue.SetKnownServerSeq("Unit", entityId, 7);
temp.Queue.ClearKnownServerSeq("Lesson", entityId);
Assert.Null(temp.Queue.GetKnownServerSeq("Lesson", entityId));
Assert.Equal(7, temp.Queue.GetKnownServerSeq("Unit", entityId));
}
[Fact]
public void ClearKnownServerSeq_UnbekannteEntitaet_TutNichtsUndWirftNicht()
{
using var temp = new TempEventQueue();
var exception = Record.Exception(() => temp.Queue.ClearKnownServerSeq("Lesson", "unbekannt"));
Assert.Null(exception);
}
/// Regression: nach einem Kontowechsel (TODO 10.3.5, z.B. Login-Korrektur der Groß-/
/// Kleinschreibung, siehe TODO 10.2.5) sind alle lokal zwischengespeicherten ServerSeq-Werte
/// bedeutungslos - sie beziehen sich auf das Event-Log eines ANDEREN Server-Kontos.
[Fact]
public void ResetKnownServerSeqs_EntferntAlleEintraege()
{
using var temp = new TempEventQueue();
temp.Queue.SetKnownServerSeq("Lesson", "a", 1);
temp.Queue.SetKnownServerSeq("Unit", "b", 2);
temp.Queue.ResetKnownServerSeqs();
Assert.Null(temp.Queue.GetKnownServerSeq("Lesson", "a"));
Assert.Null(temp.Queue.GetKnownServerSeq("Unit", "b"));
}
private static SyncEvent MakeEvent() => new()
{
DeviceId = "desktop-1",
DeviceType = DeviceType.Desktop,
EntityType = "Student",
EntityId = Guid.NewGuid().ToString(),
Operation = "Save",
Payload = "{}",
};
private sealed class TempEventQueue : IDisposable
{
private readonly string _directory = Path.Combine(
Path.GetTempPath(), $"lehrerapp-sync-tests-eventqueue-{Guid.NewGuid():N}");
public EventQueue Queue { get; }
public TempEventQueue()
{
Directory.CreateDirectory(_directory);
Queue = new EventQueue(Path.Combine(_directory, "queue.db"));
}
public void Dispose()
{
Queue.Dispose();
if (Directory.Exists(_directory)) Directory.Delete(_directory, recursive: true);
}
}
}