Inkonsistenter Flask/Mongodb-Webapp-Test
-
13-12-2019 - |
Frage
Ich habe einen Flask-Integrationstest, der von einem 1-Knoten-Mongodb unterstützt wird, der zufällig fehlschlägt:
pytest/test_webapi.py:59: in test_register_test
> assert res.status_code == 302
E assert <Response streamed [404 NOT FOUND]>.status_code == 302
Die Ausfallquote liegt bei etwa 50 %.
Testen Sie test_webapi.py folgendermaßen:
def test_register_user(self):
res = self.client.get("/logout")
class MySMTPServer(smtpd.SMTPServer):
mails = []
def process_message(self, peer, mailfrom, rcpttos, data):
self.mails.append((rcpttos[0], data))
server = MySMTPServer(('localhost', 12345), None)
t = threading.Thread(target=asyncore.loop, args=(1,))
t.start()
time.sleep(.1)
try:
res = self.client.post("/register", data=self.registration)
assert res.status_code == 200
mail, hash = server.mails[0]
self.conn.fsync()
time.sleep(.1)
res = self.client.get('/activate/' + hash)
assert res.status_code == 302
finally:
server.close()
Die relevanten Flask-Methoden von webapi.py:
@app.route("/register", methods=["POST"])
def register_user():
mail = flask.request.form['mail']
user = flask.request.form["user"]
pw = flask.request.form["pass"]
hash = users.register(user, pw, mail=mail)
return flask.jsonify({'_id': None}) # XXX
@app.route('/activate/<hash>', methods=['GET'])
def activate_user(hash):
key = users.activate(hash=hash)
if not key:
flask.abort(404)
return flask.redirect("/")
...werden durch Aktionsmethoden unterstützt:
make_key = lambda : base64.encodestring(os.urandom(32)).strip()
def register(self, user, pw, **kw):
hash = self.make_key()
user = self.new(user, pw, activation=hash, **kw)
self._send_mail(**user)
return hash
def activate(self, hash):
user = self.users.find_one({'activation': hash})
if not user:
return None
key = self.make_key()
activation = {
'$unset': {'activation': 1},
'$set': {'status': 'active', 'key': key} }
self.users.update({'_id': user['_id']}, activation)
return user
...Dabei ist self.users eine Mongodb-Sammlung.
self.new() behält die Entität mit „safe=True“ bei.
Interessanterweise scheint dieses Problem bei mehreren anderen Tests, die ähnliche Dinge durchführen, nie aufzutreten.
Ich hatte gedacht, dass dies ausreichen würde, um sicherzustellen, dass das persistente Objekt für andere Threads im Pymongo-Verbindungspool sichtbar wäre.Welchen Teil der Mongodb/Pymongo-Dokumentation hätte ich sorgfältiger lesen sollen?Oder gibt es eine seltsame Interaktion mit Asyncore?
Lösung
(portiert aus dem Kommentarthread)
Im Rahmen der Tests ist das data
Wert nur die Base64-codierte Zeichenfolge des Aktivierungsschlüssels?base64 enthält Buchstaben und Ziffern, aber auch „+“ und „/“, die beide von URL-Parsern falsch interpretiert werden (insbesondere „/“).