Files
tryton-db-migration/doc/TESTDATEN.md
T
uha4 a55774eff2 neues skript sql_dump_diff.py zum Vergleich von 2 sql-dumps.
- leere, frisch initialisierte Datenbanken der Versionen verglichen
- datasetprogramme erkennen jetzt auch suche nach standardtabellen wie uom
2026-08-22 17:45:46 +02:00

132 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Proteus-Testdaten-Pipeline
Ergänzender Ansatz zur [Codeanalyse](UPDATEANALYSE.md): Statt den
`__register__`-Code zu lesen, wird ein deklarativ definierter Testdatensatz
über Proteus in zwei frisch installierten Tryton-Instanzen (5.0 und 8.0)
tatsächlich angelegt. Ziel ist, dieselbe Datei gegen beide Versionen laufen
zu lassen, damit sowohl die Skript-Ausgabe (`compare_snapshots.py`) als
auch anschließend die SQL-Dumps beider Datenbanken vergleichbar sind -
dafür müssen inhaltlich identische Daten in derselben Reihenfolge
eingespielt werden.
## Workflow
```
tests/scenario_*.rst (Tryton-Repo, pro Modul)
│ rst_to_dataset.py
▼
rsts/<version>e/*.yaml (ein YAML-Record pro angelegtem Proteus-Objekt)
│ rsts_merge_dedup.py
▼
reports/<version>_testdata_merged.yaml (dedupliziert, abhängigkeitskorrekt sortiert)
│ create_dataset.py --database ...
▼
snapshot_<version>.json
│ compare_snapshots.py snapshot_a.json snapshot_b.json
▼
Fund-Liste: status_changed / value_changed / missing_record
```
### 1. `rst_to_dataset.py` – Testdaten aus den Modul-eigenen Tests extrahieren
Tryton-Module bringen eigene `tests/scenario_*.rst`-Doctests mit (ausführbarer
Proteus-Code in `>>>`-Zeilen). Das Skript parst diese Dateien per AST und
erkennt:
```
>>> Party = Model.get('party.party')
>>> party = Party(name='Testfirma GmbH')
>>> party.vat_number = '123'
>>> party.save()
```
→ wird zu einem YAML-Record mit `key`, `model`, `fields`. Referenzen auf
zuvor im selben File angelegte Records werden zu `{"$ref": "..."}`,
`Decimal(...)`/`date(...)` zu `{"$decimal": ...}`/`{"$date": ...}`.
Ein weiteres, sehr häufiges Muster wird ebenfalls erkannt: Zugriff auf
bereits vorhandene Stammdaten (Länder, Währungen, Einheiten,
Standard-Lagerorte, ... - i. d. R. per XML-Fixture beim Modul-Aktivieren
angelegt, nicht Teil des eigentlichen Testdatensatzes):
```
>>> ProductUom = Model.get('product.uom')
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
```
→ wird zu `{"$search": {"model": "product.uom", "domain": [["name", "=", "Unit"]]}}`
- aufgelöst wird das erst live beim Anlegen durch `create_dataset.py`
(Schritt 3), nicht schon hier, da diese Records ja nicht selbst Teil der
YAML sind. Nur literale Domains werden erkannt (keine Variablen darin);
sonst bleibt es wie bisher `$manual`.
Alles sonst nicht automatisch Auflösbare (Wizards, `.click(...)`,
Helper-Funktionsaufrufe) wird als `{"$manual": "<Ausdruck>"}` markiert oder
ganz übersprungen - bewusst sichtbar unvollständig statt still falsch.
Record-Keys werden mit dem Dateinamen präfixiert, damit beim
Zusammenführen mehrerer Module keine Kollisionen entstehen.
### 2. `rsts_merge_dedup.py` – pro Version zusammenführen
Liest alle `rsts/<version>e/*.yaml` eines Verzeichnisses ein und entfernt
Records mit identischem `model`+`fields` (z. B. dasselbe
Basis-`product.template`, das in vielen Szenarien wiederverwendet wird).
`$ref`-Verweise auf entfernte Duplikate werden auf den behaltenen Record
umgeschrieben. Danach wird per Kahn-Algorithmus so sortiert, dass
`$ref`-Abhängigkeiten immer VOR dem referenzierenden Record stehen, aber
innerhalb der Freiheitsgrade weiterhin nach `model` gruppiert wird.
**Achtung:** Dedupliziert bewusst GLOBAL, auch innerhalb derselben Datei.
Bei Szenarien, die zwei absichtlich gleich aussehende Records anlegen (z. B.
`scenario_party_replace.rst`: zwei Parteien namens "Pam", um eine zu
ersetzen), verändert das den Sinn des Szenarios - für einen groben
Testdatensatz ist das in Ordnung, für szenario-treue Tests nicht.
### 3. `create_dataset.py` – gegen eine echte Instanz anlegen
Legt die Records der Reihe nach per Proteus an, liest jeden Wert danach
FRISCH VOM SERVER zurück (nicht aus dem lokalen Proteus-Cache), damit
automatische Reformatierung sichtbar wird. Ergebnis: ein JSON-Snapshot
(`status`/`error`/`stored` pro Record).
**Feld-Umbenennungen zwischen Versionen** (`FIELD_RENAMES`): Da dieselbe
YAML gegen mehrere Versionen laufen soll, aber Felder umbenannt werden
können (bestätigt: `stock.move.uom` → `stock.move.unit` zwischen 5.0 und
8.0), prüft das Skript pro Modell zuerst per `fields_get()`, ob der
YAML-Feldname auf dem jeweiligen Server existiert, und weicht sonst auf
einen bekannten, bidirektionalen Alias aus. Ein wirklich unbekanntes Feld
bleibt trotzdem ein Fehler - das ist ja gerade das gesuchte Signal für eine
echte Schema-Änderung. Weitere Umbenennungen bei Bedarf in `FIELD_RENAMES`
ergänzen, sobald ein Lauf sie aufdeckt.
**`$search`-Auflösung:** Werte der Form `{"$search": {"model": ...,
"domain": ...}}` (von `rst_to_dataset.py` erzeugt, siehe Schritt 1) werden
live per `Model.get(model).find(domain)` gegen den Zielserver aufgelöst -
für Stammdaten, die nicht selbst angelegt werden, sondern schon per
XML-Fixture da sind. Ergebnis wird pro Lauf gecacht (dieselbe Suche, z. B.
nach der Einheit "Unit", kommt in vielen Records vor). Kein Treffer ->
Fehler mit Klartext statt eines neu angelegten Records - das ist selbst
ein Signal, dass sich die Stammdaten zwischen den Versionen geändert
haben.
### 4. `compare_snapshots.py` – zwei Versionen gegenüberstellen
Vergleicht zwei Snapshots (gleiche YAML, zwei Versionen/Datenbanken) und
markiert `status_changed` (ein Record schlägt nur in einer Version fehl -
Kandidat für Format-/Constraint-/Pflichtfeld-Änderung), `value_changed`
(gespeicherter Wert weicht trotz gleichem Input ab - automatische
Reformatierung) und `missing_record`.
## Stand
- `rst_to_dataset.py` und `rsts_merge_dedup.py` sind gegen echte
`scenario_*.rst`-Dateien aus `/mnt/tryton` (5.0- und 8.0-Branch) getestet,
siehe `reports/5_testdata_merged.yaml` / `reports/8_testdata_merged.yaml`
(jeweils NUR aus den Szenarien der jeweiligen Version extrahiert, noch
NICHT zu einer gemeinsamen Datei zusammengeführt).
- `create_dataset.py` und `compare_snapshots.py` sind noch nicht gegen eine
echte Tryton-Instanz gelaufen (nur syntaktisch geprüft).
- Welche Modelle/Felder überhaupt Testdaten brauchen bzw. wo sich 5.0 und
8.0 tatsächlich unterscheiden, siehe [MODELLVERGLEICH.md](MODELLVERGLEICH.md)
- das steuert, wo als Nächstes von Hand YAML-Records ergänzt werden.