feat(triage): Ticket-Fixes (Daten + Code) + prod-fähige Triage
Daten-Fixes (conflict-decisions.json, re-ingest-stabil) für ~30 Tickets:
Merges (Jamie/Hiro/Mino/Jana/Blacky/Sakura/Malou/Socke→Marty), Eltern-Korrekturen
(Jacky/Idefix/Ichika/Roni/Ethan), Kruke→Kuke (+ Todesdatum), Targa-Wurf R14 + Druna,
Stacy/Merle/Domi/Eliza; Joghurt-Phantomwurf entfernt.
Code-Fixes:
- Gaida & alle Verstorbenen: Status wird aus Todesdatum/Abgabe abgeleitet
(Program.cs Startup-Sweep heilt Altfälle; IngestResolved re-derived nach Freeze).
- CoCo: Scheckungsart wird bei jeder Schecke angezeigt (Platzhalter wenn leer).
- M-Wurf/Gale: über-gemergte Fremdtiere via neuem litterChildren-Override entfernt.
- renameTo eltern-verknüpfungssicher (Quell-Name im Index); dateOfDeath als Override.
Prod-fähige Triage (API):
- GET /feedback/{id} + GET /feedback?status= (kein 2-MB-Dump).
- POST /import/ingest-resolved/upload (multipart) → Ingest gegen Prod ohne SSH.
Tests: 280 Backend, 149 Frontend, alle Python, betroffene Playwright grün.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
61
GerbilManager.Tests/ImportIngestUploadEndpointTests.cs
Normal file
61
GerbilManager.Tests/ImportIngestUploadEndpointTests.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
using System.Net;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
|
||||
namespace GerbilManager.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// POST /import/ingest-resolved/upload — Upload-Variante des Ingests: eine hochgeladene
|
||||
/// resolved_import.json wird serverseitig in den Import-Quellordner gestaged und direkt ingested.
|
||||
/// Damit lässt sich der Import gegen PROD fahren, ohne die Datei per SSH/docker cp in den Container
|
||||
/// zu kopieren. Der Test isoliert Quell-/Fotoordner über ApiFactory in Temp-Verzeichnisse.
|
||||
/// </summary>
|
||||
public class ImportIngestUploadEndpointTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task Upload_stages_resolved_json_and_runs_ingest()
|
||||
{
|
||||
var srcDir = Path.Combine(Path.GetTempPath(), "ingest-upload-" + Guid.NewGuid().ToString("N"));
|
||||
var photoDir = Path.Combine(Path.GetTempPath(), "ingest-upload-photos-" + Guid.NewGuid().ToString("N"));
|
||||
using var factory = new ApiFactory { ImportSourcePath = srcDir, PhotosRootPath = photoDir };
|
||||
var client = factory.CreateClient();
|
||||
|
||||
// Minimaler, aber valider Payload (leere Sammlungen) — genügt, um Staging + Ingest-Lauf zu prüfen.
|
||||
const string json = "{\"Gerbils\":[],\"Litters\":[],\"Contacts\":[],\"SaleContracts\":[],\"GerbilPhotos\":[]}";
|
||||
|
||||
using var form = new MultipartFormDataContent();
|
||||
var file = new ByteArrayContent(Encoding.UTF8.GetBytes(json));
|
||||
file.Headers.ContentType = new MediaTypeHeaderValue("application/json");
|
||||
form.Add(file, "resolved", "resolved_import.json");
|
||||
|
||||
var resp = await client.PostAsync("/import/ingest-resolved/upload", form);
|
||||
Assert.Equal(HttpStatusCode.OK, resp.StatusCode);
|
||||
|
||||
var body = await resp.Content.ReadAsStringAsync();
|
||||
Assert.DoesNotContain("Error:", body); // Ingest lief, keine "file not found"-Fehlermeldung
|
||||
|
||||
// Die hochgeladene Datei wurde an den erwarteten Ort gestaged.
|
||||
Assert.True(File.Exists(Path.Combine(srcDir, "resolved_import.json")));
|
||||
|
||||
try { Directory.Delete(srcDir, recursive: true); } catch { /* best effort */ }
|
||||
try { Directory.Delete(photoDir, recursive: true); } catch { /* best effort */ }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Upload_rejects_empty_file_with_400()
|
||||
{
|
||||
var srcDir = Path.Combine(Path.GetTempPath(), "ingest-upload-" + Guid.NewGuid().ToString("N"));
|
||||
using var factory = new ApiFactory { ImportSourcePath = srcDir };
|
||||
var client = factory.CreateClient();
|
||||
|
||||
using var form = new MultipartFormDataContent();
|
||||
var file = new ByteArrayContent(Array.Empty<byte>());
|
||||
file.Headers.ContentType = new MediaTypeHeaderValue("application/json");
|
||||
form.Add(file, "resolved", "resolved_import.json");
|
||||
|
||||
var resp = await client.PostAsync("/import/ingest-resolved/upload", form);
|
||||
Assert.Equal(HttpStatusCode.BadRequest, resp.StatusCode);
|
||||
|
||||
try { Directory.Delete(srcDir, recursive: true); } catch { /* best effort */ }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user