Below is an example that demonstrates the problem. Note the commented line (
from google.appengine.ext import testbed). When this line is commented, the tests work as expected.
When this line is uncommented, the
@login_required decorator for
Flask-Login stops recognizing the logged-in user i.e.
current_user.is_authenticated() returns False. It would seem the culprit is importing
#!/usr/bin/env python2.7 import unittest import sys from flask import Flask, current_app, url_for from flaskext import login sys.path.append('/usr/local/google_appengine') # Go ahead and uncomment this: # from google.appengine.ext import testbed app = Flask('test') app.secret_key = 'abc' login_manager = login.LoginManager() login_manager.setup_app(app) login_manager.login_view = 'index' class User(login.UserMixin): def get_id(self): return "1" @login_manager.user_loader def load_user(user_id): return User() @app.route('/') @login.login_required def index(): pass @login_manager.unauthorized_handler def unauthorized(): raise Exception("Unauthorized.") class MyTest(unittest.TestCase): def setUp(self): self.app = app self.client = app.test_client() def test_user(self): with self.app.test_request_context(): logged_in = login.login_user(User()) r = self.client.get('/') if __name__ == '__main__': unittest.main()
The specific exception is:
ERROR:test:Exception on / [GET] Traceback (most recent call last): File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Flask-0.8-py2.7.egg/flask/app.py", line 1504, in wsgi_app response = self.full_dispatch_request() File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Flask-0.8-py2.7.egg/flask/app.py", line 1264, in full_dispatch_request rv = self.handle_user_exception(e) File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Flask-0.8-py2.7.egg/flask/app.py", line 1262, in full_dispatch_request rv = self.dispatch_request() File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Flask-0.8-py2.7.egg/flask/app.py", line 1248, in dispatch_request return self.view_functions[rule.endpoint](**req.view_args) File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Flask_Login-0.1-py2.7.egg/flaskext/login.py", line 479, in decorated_view return current_app.login_manager.unauthorized() File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Flask_Login-0.1-py2.7.egg/flaskext/login.py", line 250, in unauthorized return self.unauthorized_callback() File "./test.py", line 34, in unauthorized raise Exception("Unauthorized.") Exception: Unauthorized.
The behaviour I would expect is that importing (and using)
testbed would have no effect on the Flask context stack and, by extension, Flask-Login would continue to work in the unit testing environment even though
testbed has been imported.
I have stared at this for a bit, to no avail, and would be grateful for any insight and suggestions for potential solutions to this problem.
Thank you for reading.
flask.gand other associated variables seem to also be unavailable - Brian M. Hunt 2012-04-03 21:59
The testbed uses separate stubs for many of the GAE services, including the datastore and user service.
I'm not familiar with flask, but if the login requires a user to exist in the database, it'll fail since the testbed uses a separate database. You'll have to load user data into the testbed database first.
Also if you include the testbed, there's some initialization calls you have to make to set up the stubs before you can use it. https://developers.google.com/appengine/docs/python/tools/localunittesting
class Userin the degenerate example above. As mentioned, the problem is not using
testbed, but that merely importing it breaks
Flask-Login- Brian M. Hunt 2012-04-03 20:32
testbedthat is called. The questions is what. I've debugged from top to bottom in pdb a few times but didn't hit it - the problem seems buried somewhere in Werkzeug. I have used evil monkey patches in the interim. : - Brian M. Hunt 2012-04-04 00:26