Warum kann Twisted's adbapi Daten innerhalb von Unit Tests nicht wiederherstellen?

8

Übersicht

Kontext

Ich schreibe Komponententests für eine Logik höherer Ordnung, die vom Schreiben in eine SQLite3-Datenbank abhängt. Dazu verwende ich twisted.trial.unittest und twisted.enterprise.adbapi.ConnectionPool .

Problemstellung

Ich kann eine persistente sqlite3-Datenbank erstellen und darin Daten speichern. Mit sqlitebrowser kann ich überprüfen, ob die Daten wie erwartet erhalten wurden.

Das Problem besteht darin, dass Aufrufe von t.e.a.ConnectionPool.run* (z. B. runQuery ) eine leere Menge von Ergebnissen zurückgeben, jedoch nur, wenn sie innerhalb von TestCase aufgerufen werden.

Hinweise und wichtige Details

Das Problem tritt nur innerhalb von Twisteds trial framework auf. Mein erster Versuch beim Debugging war, den Datenbankcode aus dem Komponententest zu ziehen und ihn in ein unabhängiges Test / Debug-Skript zu schreiben. Das Skript funktioniert wie erwartet , während der Unit-Test-Code nicht funktioniert (siehe Beispiele unten).

Fall 1: Fehlverhaltenstest

init.sql

Dies ist das Skript, das zum Initialisieren der Datenbank verwendet wird. Diese Datei enthält keine (offensichtlichen) Fehler.

%Vor%

test_sqlite.py

Dies ist die Einheitentestklasse, die unerwartet fehlschlägt. TestStateManagement.test_db_clean übergibt, gab an, dass die Tabellen ordnungsgemäß erstellt wurden. TestStateManagement.test_inode_create schlägt fehl und gibt an, dass Null-Ergebnisse abgerufen wurden.

%Vor%

sqlengine.py

Dies sind die Artefakte, die durch die obigen Komponententests getestet werden.

%Vor%

Fall 2: Bug verschwindet außerhalb von twisted.trial

%Vor%

Schlussbemerkungen

Nach dem Prüfen mit sqlitebrowser scheint es, als ob die Daten in db.sqlite geschrieben werden, so dass es aussieht wie ein Problem retrieval . Von hier aus bin ich irgendwie ratlos ... irgendwelche Ideen?

BEARBEITEN

Dieser Code erzeugt ein inode , das zum Testen verwendet werden kann.

%Vor%     
blz 24.05.2017, 13:50
quelle

2 Antworten

2

Okay, es stellt sich heraus, dass dies ein bisschen schwierig ist. Das Ausführen der Tests isoliert (wie in dieser Frage geschrieben) macht es so, dass der Fehler nur selten auftritt. Wenn es jedoch im Kontext einer ganzen Testsuite ausgeführt wird, schlägt es fast zu 100% fehl.

Ich habe yield task.deferLater(reactor, .00001, lambda: None) nach dem Schreiben in die db und vor dem Lesen aus der db hinzugefügt, und das löst das Problem.

Von da an vermutete ich, dass es sich um eine Race Condition handeln könnte, die aus dem Verbindungspool und der begrenzten Parallelitätstoleranz von SQLite herrührt. Ich habe versucht, die Parameter cb_min und cb_max auf ConnectionPool auf 1 zu setzen, und das hat auch das Problem gelöst.

Kurz gesagt: es scheint, dass sqlite nicht sehr gut mit mehreren Verbindungen funktioniert, und dass die geeignete Lösung darin besteht, die Parallelität so weit wie möglich zu vermeiden.

    
blz 29.05.2017, 13:50
quelle
-1

Wenn Sie sich Ihre setUp -Funktion ansehen, geben Sie self.db.runInteraction(...) zurück, was eine verzögerte zurückgibt. Wie Sie bereits festgestellt haben, gehen Sie davon aus, dass das Warten darauf wartet, dass das Deferred beendet wird. Dies ist jedoch nicht der Fall und es ist eine Falle, der die meisten zum Opfer fallen (ich selbst eingeschlossen). Ich werde ehrlich zu Ihnen sein, für Situationen wie diese, insbesondere für Komponententests, führe ich einfach den synchronen Code außerhalb der TestCase -Klasse aus, um die Datenbank zu initialisieren. Zum Beispiel:

%Vor%

Alternativ könnten Sie das Setup und yield runOperation(...) dekorieren, aber etwas sagt mir, dass es nicht funktionieren würde ... Auf jeden Fall ist es überraschend, dass keine Fehler aufgetreten sind.

PS

Ich habe diese Frage schon eine Weile im Kopf gehabt und seit Tagen in meinem Hinterkopf. Ein möglicher Grund dafür dämmerte mir schließlich um 1 Uhr morgens. Aber ich bin zu müde / faul, um das auszuprobieren: D, aber es ist eine verdammt gute Ahnung. Ich möchte Sie auf dieser Detailebene in dieser Frage loben.

    
notorious.no 29.05.2017 05:17
quelle