Skip to content

Instantly share code, notes, and snippets.

@peterskipper
Created October 22, 2014 18:02
Show Gist options
  • Save peterskipper/60a134a0a1eeb1d2a191 to your computer and use it in GitHub Desktop.
Save peterskipper/60a134a0a1eeb1d2a191 to your computer and use it in GitHub Desktop.
chords project tests and api
import os.path
import json
from flask import request, Response, url_for, send_from_directory
from werkzeug.utils import secure_filename
from jsonschema import validate, ValidationError
import models
import decorators
import analysis
from chords import app
from database import session
from utils import upload_path
post_schema = {
"type": "object",
"properties": {
"file":
{
"type": "object",
"properties": {
"id": {"type": "number"}
},
"required": ["id"]
}
},
"required": ["file"]
}
@app.route("/songs", methods=["GET"])
@decorators.accept("application/json")
def songs_get():
""" Get a list of songs """
# Get songs from database
songs = session.query(models.Song).all()
# Convert songs to JSON and return response
data = json.dumps([song.as_dictionary() for song in songs])
return Response(data, 200, mimetype="application/json")
@app.route("/songs", methods=["POST"])
@decorators.accept("application/json")
@decorators.require("application/json")
def songs_post():
""" Post a new song to database """
data = request.json
# Check for valid JSON. If not available, return 422, Unprocessable Entity
try:
validate(data, post_schema)
except ValidationError as error:
data = json.dumps({"message": error.message})
return Response(data, 422, mimetype="application/json")
file_id = data["file"]["id"]
song_file = session.query(models.File).get(file_id)
if not song_file: # File with id = file_id is not in database
message = "Could not find song file with file id {}".format(file_id)
data = json.dumps({"message": message})
return Response(data, 404, mimetype="application/json")
song = models.Song(file_id=file_id)
session.add(song)
session.commit()
data = json.dumps(song.as_dictionary())
return Response(data, 201, mimetype="application/json")
import unittest
import os
import shutil
import json
from urlparse import urlparse
from StringIO import StringIO
# Configure our app to use the testing databse
os.environ["CONFIG_PATH"] = "chords.config.TestingConfig"
from chords import app
from chords import models
from chords.utils import upload_path
from chords.database import Base, engine, session
class TestAPI(unittest.TestCase):
""" Tests for the chords API """
def setUp(self):
""" Test setup """
self.client = app.test_client()
# Set up the tables in the database
Base.metadata.create_all(engine)
# Create folder for test uploads
os.mkdir(upload_path())
def testGetEmptySongs(self):
""" Query Empty Song List """
response = self.client.get("/songs",
headers=[("Accept", "application/json")]
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.mimetype, "application/json")
data = json.loads(response.data)
self.assertEqual(data, [])
def testGetSongs(self):
""" Query Song List """
# Add files and songs to db
file1 = models.File(name="SongFile 1")
file2 = models.File(name="SongFile 2")
session.add_all([file1, file2])
session.commit()
song1 = models.Song(file_id=file1.id)
song2 = models.Song(file_id=file2.id)
session.add_all([song1, song2])
session.commit()
response = self.client.get("/songs",
headers=[("Accept","application/json")]
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.mimetype, "application/json")
songs = json.loads(response.data)
self.assertEqual(len(songs), 2)
song1 = songs[0]
self.assertEqual(song1["id"], 1)
self.assertEqual(song1["file"]["id"], 1)
self.assertEqual(song1["file"]["name"], "SongFile 1")
song2 = songs[1]
self.assertEqual(song2["id"], 2)
self.assertEqual(song2["file"]["id"], 2)
self.assertEqual(song2["file"]["name"], "SongFile 2")
def testUnsupportedAcceptHeader(self):
response = self.client.get("/songs",
headers=[("Accept", "application/xml")]
)
self.assertEqual(response.status_code, 406)
self.assertEqual(response.mimetype, "application/json")
data = json.loads(response.data)
self.assertEqual(data["message"],
"Request must accept application/json data")
def testPostSong(self):
""" Posting a new Song to db """
# Add a new file to db
file1 = models.File(name="Happy Birthday")
session.add(file1)
session.commit()
# Add a new song via endpoint
song = {
"file": {
"id": 1
}
}
response = self.client.post("/songs",
data=json.dumps(song),
content_type="application/json",
headers=[("Accept", "application/json")]
)
self.assertEqual(response.status_code, 201)
self.assertEqual(response.mimetype, "application/json")
# Check response data
data = json.loads(response.data)
self.assertEqual(data["id"], 1)
self.assertEqual(data["file"]["id"], 1)
self.assertEqual(data["file"]["name"], "Happy Birthday")
# Check db
songs = session.query(models.Song).all()
self.assertEqual(len(songs), 1)
song = songs[0]
self.assertEqual(song.file_id, file1.id)
self.assertEqual(song.file.name, "Happy Birthday")
self.assertEqual(song.file.id, 1)
def testPostNonExistentSong(self):
""" Post A Song With No File """
song = {
"file": {
"id": 1
}
}
response = self.client.post("/songs",
data=json.dumps(song),
content_type="application/json",
headers=[("Accept", "application/json")]
)
self.assertEqual(response.status_code, 404)
self.assertEqual(response.mimetype, "application/json")
data = response.data
data = json.loads(data)
self.assertEqual(data["message"], "Could not find song file with file id 1")
def testUnsupportedMimetype(self):
data = "<xml></xml>"
response = self.client.post("/songs",
data = json.dumps(data),
content_type="application/xml",
headers=[("Accept", "application/json")]
)
self.assertEqual(response.status_code, 415)
self.assertEqual(response.mimetype, "application/json")
data = json.loads(response.data)
self.assertEqual(data["message"],
"Request must contain application/json data")
def testMissingData(self):
""" Posting a post with a missing body """
song = {
"file": {}
}
response = self.client.post("/songs",
data=json.dumps(song),
content_type="application/json",
headers=[("Accept", "application/json")]
)
self.assertEqual(response.status_code, 422)
data = json.loads(response.data)
self.assertEqual(data["message"], "'id' is a required property")
def testInvalidData(self):
""" Posting a post with an invalid body """
song = {
"file": {
"id": "not_an_id"
}
}
response = self.client.post("/songs",
data=json.dumps(song),
content_type="application/json",
headers=[("Accept", "application/json")]
)
self.assertEqual(response.status_code, 422)
data = json.loads(response.data)
data["message"] = data["message"][1:]
self.assertEqual(data["message"], "'not_an_id' is not of type 'number'")
def tearDown(self):
""" Test teardown """
# Remove the tables and their data from the database
Base.metadata.drop_all(engine)
# Delete test upload folder
shutil.rmtree(upload_path())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment