Files
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

6.1 KiB
Raw Permalink Blame History

Proteus-Testdaten-Pipeline

Ergänzender Ansatz zur Codeanalyse: 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
    • das steuert, wo als Nächstes von Hand YAML-Records ergänzt werden.