From 8c091d7add8dcc9b0587eed1b7060ae6a2fe5106 Mon Sep 17 00:00:00 2001 From: Miguel Grinberg Date: Sun, 16 Dec 2012 00:32:38 -0800 Subject: [PATCH] unit testing framework --- app/__init__.py | 22 ++++++++++++++++++++- app/forms.py | 18 ++++++++++++++++++ app/models.py | 14 +++++++++++++- app/templates/404.html | 7 +++++++ app/templates/500.html | 8 ++++++++ app/templates/edit.html | 7 ++++++- app/views.py | 15 ++++++++++++--- config.py | 11 ++++++++++- runp.py | 3 +++ tests.py | 42 +++++++++++++++++++++++++++++++++++++++++ 10 files changed, 140 insertions(+), 7 deletions(-) create mode 100644 app/templates/404.html create mode 100644 app/templates/500.html create mode 100755 runp.py create mode 100755 tests.py diff --git a/app/__init__.py b/app/__init__.py index c7a1b90..4e5b345 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -3,7 +3,7 @@ from flask import Flask from flask.ext.sqlalchemy import SQLAlchemy from flask.ext.login import LoginManager from flask.ext.openid import OpenID -from config import basedir +from config import basedir, ADMINS, MAIL_SERVER, MAIL_PORT, MAIL_USERNAME, MAIL_PASSWORD app = Flask(__name__) app.config.from_object('config') @@ -13,5 +13,25 @@ lm.setup_app(app) lm.login_view = 'login' oid = OpenID(app, os.path.join(basedir, 'tmp')) +if not app.debug: + import logging + from logging.handlers import SMTPHandler + credentials = None + if MAIL_USERNAME or MAIL_PASSWORD: + credentials = (MAIL_USERNAME, MAIL_PASSWORD) + mail_handler = SMTPHandler((MAIL_SERVER, MAIL_PORT), 'no-reply@' + MAIL_SERVER, ADMINS, 'microblog failure', credentials) + mail_handler.setLevel(logging.ERROR) + app.logger.addHandler(mail_handler) + +if not app.debug: + import logging + from logging.handlers import RotatingFileHandler + file_handler = RotatingFileHandler('tmp/microblog.log', 'a', 1 * 1024 * 1024, 10) + file_handler.setLevel(logging.INFO) + file_handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]')) + app.logger.addHandler(file_handler) + app.logger.setLevel(logging.INFO) + app.logger.info('microblog startup') + from app import views, models diff --git a/app/forms.py b/app/forms.py index 3f4e4f0..d8bf857 100644 --- a/app/forms.py +++ b/app/forms.py @@ -1,5 +1,6 @@ from flask.ext.wtf import Form, TextField, BooleanField, TextAreaField from flask.ext.wtf import Required, Length +from app.models import User class LoginForm(Form): openid = TextField('openid', validators = [Required()]) @@ -8,3 +9,20 @@ class LoginForm(Form): class EditForm(Form): nickname = TextField('nickname', validators = [Required()]) about_me = TextAreaField('about_me', validators = [Length(min = 0, max = 140)]) + + def __init__(self, original_nickname, *args, **kwargs): + Form.__init__(self, *args, **kwargs) + self.original_nickname = original_nickname + + def validate(self): + if not Form.validate(self): + return False + if self.nickname.data == self.original_nickname: + return True + user = User.query.filter_by(nickname = self.nickname.data).first() + if user != None: + self.nickname.errors.append('This nickname is already in use. Please choose another one.') + return False + return True + + diff --git a/app/models.py b/app/models.py index cbd73d5..4fbbfd1 100644 --- a/app/models.py +++ b/app/models.py @@ -12,7 +12,19 @@ class User(db.Model): posts = db.relationship('Post', backref = 'author', lazy = 'dynamic') about_me = db.Column(db.String(140)) last_seen = db.Column(db.DateTime) - + + @staticmethod + def make_unique_nickname(nickname): + if User.query.filter_by(nickname = nickname).first() == None: + return nickname + version = 2 + while True: + new_nickname = nickname + str(version) + if User.query.filter_by(nickname = new_nickname).first() == None: + break + version += 1 + return new_nickname + def is_authenticated(self): return True diff --git a/app/templates/404.html b/app/templates/404.html new file mode 100644 index 0000000..203c070 --- /dev/null +++ b/app/templates/404.html @@ -0,0 +1,7 @@ + +{% extends "base.html" %} + +{% block content %} +

File Not Found

+

Back

+{% endblock %} \ No newline at end of file diff --git a/app/templates/500.html b/app/templates/500.html new file mode 100644 index 0000000..994d77c --- /dev/null +++ b/app/templates/500.html @@ -0,0 +1,8 @@ + +{% extends "base.html" %} + +{% block content %} +

An unexpected error has occurred

+

The administrator has been notified. Sorry for the inconvenience!

+

Back

+{% endblock %} \ No newline at end of file diff --git a/app/templates/edit.html b/app/templates/edit.html index 2f4e252..5f36c65 100644 --- a/app/templates/edit.html +++ b/app/templates/edit.html @@ -8,7 +8,12 @@ - + diff --git a/app/views.py b/app/views.py index d3f1772..be755b3 100644 --- a/app/views.py +++ b/app/views.py @@ -16,7 +16,16 @@ def before_request(): g.user.last_seen = datetime.utcnow() db.session.add(g.user) db.session.commit() - + +@app.errorhandler(404) +def internal_error(error): + return render_template('404.html'), 404 + +@app.errorhandler(500) +def internal_error(error): + db.session.rollback() + return render_template('500.html'), 500 + @app.route('/') @app.route('/index') @login_required @@ -94,7 +103,7 @@ def user(nickname): @app.route('/edit', methods = ['GET', 'POST']) @login_required def edit(): - form = EditForm() + form = EditForm(g.user.nickname) if form.validate_on_submit(): g.user.nickname = form.nickname.data g.user.about_me = form.about_me.data @@ -102,7 +111,7 @@ def edit(): db.session.commit() flash('Your changes have been saved.') return redirect(url_for('edit')) - else: + elif request.method != "POST": form.nickname.data = g.user.nickname form.about_me.data = g.user.about_me return render_template('edit.html', diff --git a/config.py b/config.py index 5aafd2a..63e2380 100644 --- a/config.py +++ b/config.py @@ -12,4 +12,13 @@ OPENID_PROVIDERS = [ { 'name': 'MyOpenID', 'url': 'https://www.myopenid.com' }] SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'app.db') -SQLALCHEMY_MIGRATE_REPO = os.path.join(basedir, 'db_repository') \ No newline at end of file +SQLALCHEMY_MIGRATE_REPO = os.path.join(basedir, 'db_repository') + +# mail server settings +MAIL_SERVER = 'localhost' +MAIL_PORT = 25 +MAIL_USERNAME = None +MAIL_PASSWORD = None + +# administrator list +ADMINS = ['you@example.com'] diff --git a/runp.py b/runp.py new file mode 100755 index 0000000..dd5945b --- /dev/null +++ b/runp.py @@ -0,0 +1,3 @@ +#!flask/bin/python +from app import app +app.run(debug = False) diff --git a/tests.py b/tests.py new file mode 100755 index 0000000..dbb44ac --- /dev/null +++ b/tests.py @@ -0,0 +1,42 @@ +#!flask/bin/python +import os +import unittest + +from config import basedir +from app import app, db +from app.models import User + +class TestCase(unittest.TestCase): + def setUp(self): + app.config['TESTING'] = True + app.config['CSRF_ENABLED'] = False + app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'test.db') + db.create_all() + + def tearDown(self): + db.drop_all() + + def test_avatar(self): + # create a user + u = User(nickname = 'john', email = 'john@example.com') + avatar = u.avatar(128) + expected = 'http://www.gravatar.com/avatar/d4c74594d841139328695756648b6bd6' + assert avatar[0:len(expected)] == expected + + def test_make_unique_nickname(self): + # create a user and write it to the database + u = User(nickname = 'john', email = 'john@example.com') + db.session.add(u) + db.session.commit() + nickname = User.make_unique_nickname('john') + assert nickname != 'john' + # make another user with the new nickname + u = User(nickname = nickname, email = 'susan@example.com') + db.session.add(u) + db.session.commit() + nickname2 = User.make_unique_nickname('john') + assert nickname2 != 'john' + assert nickname2 != nickname + +if __name__ == '__main__': + unittest.main() \ No newline at end of file
Your nickname:{{form.nickname(size = 24)}} + {{form.nickname(size = 24)}} + {% for error in form.errors.nickname %} +
[{{error}}] + {% endfor %} +
About yourself: