Permalink
Browse files

backend tests

  • Loading branch information...
zackdever committed Nov 27, 2012
1 parent c89211c commit 884ae3a6a2be6b84638e35f12d39ac7caf8e5aa6
View
@@ -31,6 +31,10 @@ $ python runserver.py
Test
----
+The backend is decently tested, though there is a problem with the current_user
+alias provided by the Flask-Login extension which is preventing testing of some sections.
+There are test written, but they are hidden behind 2 `if False:` statements for now.
+
```shell
$ python runtests.py
```
View
@@ -8,26 +8,39 @@
from location.auth import auth, setup_auth
from location.ui import ui
-# create a Flask app, force SSL when debug is False
-app = Flask(__name__, static_folder='./ui/static')
-app.config.from_pyfile('config.py')
+def init_app(db_name=None):
+ """Initialize the app.
-# set the below env var to your config file path to load custom configs
-CONFIG_FILE_VAR = 'LOCATION_CONFIG'
+ Because the database name has to be set before the app inits,
+ we allow it to be passed in outside of configs, because we can't
+ set it on app.config['DATABASE'] before we actually have an app.
-if os.environ.get(CONFIG_FILE_VAR) is not None:
- app.config.from_envvar(CONFIG_FILE_VAR)
+ This is mainly for testing, because it could be set via env vars,
+ but we don't want the test to override any env vars that are already set.
+ """
-# setup
-app.db = db.connect()
-setup_auth(app)
-SSLify(app, subdomains=True)
+ # create a Flask app, force SSL when debug is False
+ app = Flask(__name__, static_folder='./ui/static')
+ app.config.from_pyfile('config.py')
-# register blueprints
-app.register_blueprint(api, url_prefix='/api')
-app.register_blueprint(auth)
-app.register_blueprint(ui)
+ # load custom config file
+ custom_config = app.config['CUSTOM_CONFIG_PATH']
+ if os.environ.get(custom_config) is not None:
+ app.config.from_envvar(custom_config)
+
+ # setup
+ app.db = db.connect(db_name)
+ setup_auth(app)
+ SSLify(app, subdomains=True)
+
+ # register blueprints
+ app.register_blueprint(api, url_prefix='/api')
+ app.register_blueprint(auth)
+ app.register_blueprint(ui)
+
+ return app
def run_server():
"""Starts the server, as you might expect."""
+ app = init_app()
app.run(host=app.config['HOST'], port=app.config['PORT'])
View
@@ -23,13 +23,13 @@ class Location:
@staticmethod
def flatten(data):
"""Convert from Python to JSON."""
-
- data['id'] = str(data['_id'])
- del data['_id']
+ flat = data.copy()
+ flat['id'] = str(data['_id'])
+ del flat['_id']
# don't make owner public
- del data['owner']
- return data
+ del flat['owner']
+ return flat
@staticmethod
def from_json(data, required_id=None):
View
@@ -30,3 +30,6 @@
# import os
# os.urandom(24)
SECRET_KEY = environ.get('LOCATION_SECRET_KEY') or """LK\xce6\xac"\x05R\xe1\xaa\x85\x8ctK\xc2\n\xef\x0f\x84\xf7`&\x1d7"""
+
+# The file path to a custom config file
+CUSTOM_CONFIG_PATH = 'LOCATION_CONFIG'
View
@@ -5,11 +5,13 @@
# This way it's that much easier to use in other Python projects.
import config
-def connect():
+def connect(db_name):
"""Connect to the database and ensure indexes."""
conn = Connection(config.DB_HOST, config.DB_PORT)
- db = conn[config.DATABASE]
+
+ db_name = db_name if db_name is not None else config.DATABASE
+ db = conn[db_name]
if config.DB_USER and config.DB_PW:
db.authenticate(config.DB_USER, config.DB_PW)
View
@@ -0,0 +1,52 @@
+import json
+import unittest
+
+import location
+
+class RequestBaseTest(unittest.TestCase):
+ """Base test case for any test involving request."""
+
+ test_location = {
+ 'address' : '123 Main St.',
+ 'lat' : '127.0', # forgive numbers coming as strings
+ 'lng' : -42,
+ 'name' : 'nowhere',
+ }
+
+ def setUp(self):
+ """Create a new app, test client, and database for each test."""
+ self.app = location.init_app(db_name='location_test')
+ self.app.config['TESTING'] = True
+
+ self.test_user = { 'username': 'foo', 'password': 'jklshwensldkjhsaidfhosjd' }
+
+ self.client = self.app.test_client()
+
+ def tearDown(self):
+ """Remove the test database."""
+ self.app.db.connection.drop_database(self.app.db.name)
+
+ def register(self, username, password):
+ """Register a user with the given username and password."""
+ return self.client.post('/register', data=locals(), follow_redirects=True)
+
+ def login(self, username, password):
+ """Login a user with the given username and password."""
+ return self.client.post('/login', data=locals(), follow_redirects=True)
+
+ def logout(self):
+ """Logout the user, if any."""
+ return self.client.get('/logout', follow_redirects=True)
+
+ def login_test_user(self):
+ """Create a dummy test user and log it in."""
+ self.register(self.test_user['username'], self.test_user['password'])
+
+ def json_args(self, data=None):
+ """Make a application/json request."""
+ return { 'content_type': 'application/json', 'data': json.dumps(data) }
+
+ def relative_location(self, resp):
+ """Given a Response with a Location header, parse the relative uri."""
+ return 'api%s' % resp.headers['Location'].split('api')[1]
+
View
@@ -1,10 +1,13 @@
#!/usr/bin/env python
from testapi import test as api
+from testauth import test as auth
+from testmodels import test as models
def test():
api()
-
+ auth()
+ models()
if __name__ == '__main__':
test()
View
@@ -1,14 +1,136 @@
#!/usr/bin/env python
+import json
import unittest
-class TestAPI(unittest.TestCase):
+from location.test import RequestBaseTest
- def setUp(self):
- pass
+class TestAPI(RequestBaseTest):
+ """Test CRUD operations on Location API."""
- def test_fail(self):
- self.assertFalse(True, 'There are no tests...')
+ def test_get_collection(self):
+ """Test that a JSON list of Locations is returned."""
+ self.login_test_user()
+
+ # should have an empty list
+ resp = self.client.get('/api/locations/', **self.json_args())
+ self.assertEqual(resp.status_code, 200)
+ self.assertEqual(len(json.loads(resp.data)), 0)
+
+ # create a location
+ resp = self.client.post('/api/locations/', **self.json_args(data=self.test_location))
+ resp = self.client.get('/api/locations/', **self.json_args())
+ self.assertEqual(len(json.loads(resp.data)), 1)
+
+ # create another location
+ resp = self.client.post('/api/locations/', **self.json_args(data=self.test_location))
+ resp = self.client.get('/api/locations/', **self.json_args())
+ self.assertEqual(len(json.loads(resp.data)), 2)
+
+ def test_post(self):
+ """Test the creation of a new Location."""
+ self.login_test_user()
+
+ location = {
+ 'address' : '42 Loop',
+ 'lat' : 100.91,
+ 'lng' : 23.3,
+ 'name' : 'somewhere',
+ }
+
+ # create a new location
+ resp = self.client.post('/api/locations/', **self.json_args(data=location))
+ self.assertEqual(resp.status_code, 201)
+ relative = self.relative_location(resp)
+ resp = self.client.get(relative, **self.json_args())
+
+ # check that the data is correct
+ actual = json.loads(resp.data)
+ self.assertEqual(actual['address'], location['address'])
+ self.assertEqual(actual['lat'], location['lat'])
+ self.assertEqual(actual['lng'], location['lng'])
+ self.assertEqual(actual['name'], location['name'])
+ self.assertIsNotNone(actual['id'])
+
+ def test_get_single(self):
+ """Test that we can get a single Location."""
+ self.login_test_user()
+
+ # create a new location
+ resp = self.client.post('/api/locations/', **self.json_args(data=self.test_location))
+
+ # make sure we can get it back
+ relative = self.relative_location(resp)
+ resp = self.client.get(relative, **self.json_args())
+ self.assertEqual(resp.status_code, 200)
+
+ def test_put(self):
+ """Test updates on Location properties."""
+ self.login_test_user()
+
+ # create the normal test location
+ resp = self.client.post('/api/locations/', **self.json_args(data=self.test_location))
+ relative = self.relative_location(resp)
+
+ # change the name
+ updated = json.loads(resp.data).copy()
+ updated['name'] = 'some place special'
+
+ # put the changes on the server
+ resp = self.client.put(relative, **self.json_args(data=updated))
+ actual = json.loads(resp.data).copy()
+
+ # verify that they saved
+ self.assertEqual(actual['address'], updated['address'])
+ self.assertEqual(actual['lat'], updated['lat'])
+ self.assertEqual(actual['lng'], updated['lng'])
+ self.assertEqual(actual['name'], updated['name'])
+ self.assertIsNotNone(actual['id'])
+
+ self.assertNotEqual(actual['name'], self.test_location['name'])
+
+
+ def test_delete(self):
+ """Test tha deletes do in fact remove the Location."""
+ self.login_test_user()
+
+ # start at 0
+ resp = self.client.get('/api/locations/', **self.json_args())
+ self.assertEqual(len(json.loads(resp.data)), 0)
+
+ # add one
+ resp = self.client.post('/api/locations/', **self.json_args(data=self.test_location))
+ one = self.relative_location(resp)
+ resp = self.client.get('/api/locations/', **self.json_args())
+ self.assertEqual(len(json.loads(resp.data)), 1)
+ resp = self.client.get(one, **self.json_args())
+ self.assertEqual(resp.status_code, 200)
+
+ # add another
+ resp = self.client.post('/api/locations/', **self.json_args(data=self.test_location))
+ two = self.relative_location(resp)
+ resp = self.client.get('/api/locations/', **self.json_args())
+ self.assertEqual(len(json.loads(resp.data)), 2)
+ resp = self.client.get(two, **self.json_args())
+ self.assertEqual(resp.status_code, 200)
+
+ # delete the first location
+ resp = self.client.delete(one, **self.json_args())
+ self.assertEqual(resp.status_code, 204)
+ resp = self.client.get('/api/locations/', **self.json_args())
+ self.assertEqual(len(json.loads(resp.data)), 1)
+ resp = self.client.get(one, **self.json_args())
+ self.assertEqual(resp.status_code, 404)
+ resp = self.client.get(two, **self.json_args())
+ self.assertEqual(resp.status_code, 200)
+
+ # delete the second location
+ resp = self.client.delete(two, **self.json_args())
+ self.assertEqual(resp.status_code, 204)
+ resp = self.client.get('/api/locations/', **self.json_args())
+ self.assertEqual(len(json.loads(resp.data)), 0)
+ resp = self.client.get(two, **self.json_args())
+ self.assertEqual(resp.status_code, 404)
def test():
suite = unittest.TestLoader().loadTestsFromTestCase(TestAPI)
Oops, something went wrong.

0 comments on commit 884ae3a

Please sign in to comment.