Skip to content

Commit

Permalink
Revert "Starting tests rewrite."
Browse files Browse the repository at this point in the history
This reverts commit 223d144.
  • Loading branch information
Anderycks committed Feb 8, 2017
1 parent 223d144 commit 5461eed
Show file tree
Hide file tree
Showing 14 changed files with 334 additions and 689 deletions.
199 changes: 113 additions & 86 deletions tests/app.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
"""
SQLAlchemy JSONAPI Test App.
This app implements the backend of a web forum. It's rather simple but
provides us with a more comprehensive example for testing.
Colton Provias <[email protected]>
MIT License
"""
Expand All @@ -12,15 +9,13 @@

from flask import Flask, request
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import Boolean, Column, Enum, ForeignKey, Unicode, UnicodeText
from sqlalchemy import Boolean, Column, ForeignKey, Unicode, UnicodeText
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import backref, relationship, validates
from sqlalchemy_utils import (EmailType, IPAddressType, PasswordType,
Timestamp, URLType, UUIDType)

import enum

# ================================ APP CONFIG ================================
from sqlalchemy_jsonapi import (INTERACTIVE_PERMISSIONS, Endpoint,
FlaskJSONAPI, Method, Permissions,
permission_test)
from sqlalchemy_utils import EmailType, PasswordType, Timestamp, UUIDType

app = Flask(__name__)

Expand All @@ -31,117 +26,149 @@
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://'
app.config['SQLALCHEMY_ECHO'] = False

#api = FlaskJSONAPI(app, db)

# ================================== MODELS ==================================
class User(Timestamp, db.Model):
"""Quick and dirty user model."""


class User(db.Model, Timestamp):
#: If __jsonapi_type__ is not provided, it will use the class name instead.
__tablename__ = 'users'

id = Column(UUIDType, default=uuid4, primary_key=True, nullable=False)
id = Column(UUIDType, default=uuid4, primary_key=True)
username = Column(Unicode(30), unique=True, nullable=False)
email = Column(EmailType, nullable=False)
display_name = Column(Unicode(100), nullable=False)
password = Column(PasswordType(schemes=['bcrypt']), nullable=False)
password = Column(
PasswordType(schemes=['bcrypt']),
nullable=False)
is_admin = Column(Boolean, default=False)
last_ip_address = Column(IPAddressType)
website = Column(URLType)

@hybrid_property
def total_comments(self):
"""
Total number of comments.
Provides an example of a computed property.
"""
return self.comments.count()

@validates('email')
def validate_email(self, key, email):
"""Strong email validation."""
assert '@' in email, 'Not an email'
return email

@validates('username')
def validate_username(self, key, username):
"""
Check the length of the username.
Here's hoping nobody submits something in unicode that is 31 characters
long!!
"""
assert len(username) >= 4 and len(
username) <= 30, 'Must be 4 to 30 characters long.'
return username

@validates('password')
def validate_password(self, key, password):
"""Validate a password's length."""
assert len(password) >= 5, 'Password must be 5 characters or longer.'
return password

@jsonapi_access(Permissions.VIEW, 'password')
def view_password(self):
""" Never let the password be seen. """
return False

@jsonapi_access(Permissions.EDIT)
def prevent_edit(self):
""" Prevent editing for no reason. """
if request.view_args['api_type'] == 'blog-posts':
return True
return False

@jsonapi_access(Permissions.DELETE)
def allow_delete(self):
""" Just like a popular social media site, we won't delete users. """
return False


class BlogPost(Timestamp, db.Model):
"""Post model, as if this is a blog."""

class Forum(db.Model, Timestamp):
__tablename__ = 'forums'

id = Column(UUIDType, default=uuid4, primary_key=True, nullable=False)
name = Column(Unicode(255), nullable=False)
can_public_read = Column(Boolean, default=True)
can_public_write = Column(Boolean, default=True)


class Thread(db.Model, Timestamp):
__tablename__ = 'threads'

id = Column(UUIDType, default=uuid4, primary_key=True, nullable=False)
forum_id = Column(UUIDType, ForeignKey('forums.id'), nullable=False)
started_by_id = Column(UUIDType, ForeignKey('users.id'), nullable=False)
title = Column(Unicode(255), nullable=False)


class Post(db.Model, Timestamp):
__tablename__ = 'posts'

id = Column(UUIDType, default=uuid4, primary_key=True, nullable=False)
user_id = Column(UUIDType, ForeignKey('posts.id'), nullable=False)
id = Column(UUIDType, default=uuid4, primary_key=True)
title = Column(Unicode(100), nullable=False)
slug = Column(Unicode(100))
content = Column(UnicodeText, nullable=False)
is_removed = Column(Boolean, default=False)

is_published = Column(Boolean, default=False)
author_id = Column(UUIDType, ForeignKey('users.id'))

class ReportTypes(enum.Enum):
USER = 0
POST = 1
author = relationship('User',
lazy='joined',
backref=backref('posts', lazy='dynamic'))

@validates('title')
def validate_title(self, key, title):
"""Keep titles from getting too long."""
assert len(title) >= 5 or len(
title) <= 100, 'Must be 5 to 100 characters long.'
return title

class Report(db.Model, Timestamp):
__tablename__ = 'reports'
@jsonapi_access(Permissions.VIEW)
def allow_view(self):
""" Hide unpublished. """
return self.is_published

id = Column(UUIDType, default=uuid4, primary_key=True, nullable=False)
report_type = Column(Enum(ReportTypes), nullable=False)
reporter_id = Column(UUIDType, ForeignKey('users.id'), nullable=False)
complaint = Column(UnicodeText, nullable=False)
@jsonapi_access(INTERACTIVE_PERMISSIONS, 'logs')
def prevent_altering_of_logs(self):
return False

__mapper_args__ = {
'polymorphic_identity': 'employee',
'polymorphic_on': report_type,
'with_polymorphic': '*'
}

class BlogComment(Timestamp, db.Model):
"""Comment for each Post."""

class UserReport(db.Model):
__tablename__ = 'user_reports'
__tablename__ = 'comments'

id = Column(
UUIDType,
ForeignKey('reports.id'),
default=uuid4,
primary_key=True,
nullable=False)
user_id = Column(UUIDType, ForeignKey('users.id'), nullable=False)

__mapper_args__ = {'polymorphic_identity': ReportTypes.USER}
id = Column(UUIDType, default=uuid4, primary_key=True)
post_id = Column(UUIDType, ForeignKey('posts.id'))
author_id = Column(UUIDType, ForeignKey('users.id'), nullable=False)
content = Column(UnicodeText, nullable=False)

post = relationship('BlogPost',
lazy='joined',
backref=backref('comments', lazy='dynamic'))
author = relationship('User',
lazy='joined',
backref=backref('comments',
lazy='dynamic'))

class PostReport(db.Model):
__tablename__ = 'post_reports'

id = Column(
UUIDType,
ForeignKey('reports.id'),
default=uuid4,
primary_key=True,
nullable=False)
post_id = Column(UUIDType, ForeignKey('posts.id'), nullable=False)
class Log(Timestamp, db.Model):
__tablename__ = 'logs'
id = Column(UUIDType, default=uuid4, primary_key=True)
post_id = Column(UUIDType, ForeignKey('posts.id'))
user_id = Column(UUIDType, ForeignKey('users.id'))

__mapper_args__ = {'polymorphic_identity': ReportTypes.POST}
post = relationship('BlogPost',
lazy='joined',
backref=backref('logs', lazy='dynamic'))
user = relationship('User',
lazy='joined',
backref=backref('logs', lazy='dynamic'))

# ============================== EVENT HANDLERS ==============================
@jsonapi_access(INTERACTIVE_PERMISSIONS)
def block_interactive(cls):
return False


@app.before_request
def handle_auth():
pass
api = FlaskJSONAPI(app, db)

# ============================== API OVERRIDES ==============================

#@api.wrap_handler(['blog-posts'], [Method.GET], [Endpoint.COLLECTION])
#def sample_override(next, *args, **kwargs):
# return next(*args, **kwargs)
@api.wrap_handler(['blog-posts'], [Method.GET], [Endpoint.COLLECTION])
def sample_override(next, *args, **kwargs):
return next(*args, **kwargs)

# ================================ APP RUNNER ================================

if __name__ == '__main__':
app.run()
81 changes: 67 additions & 14 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,18 @@

import json

import jsonschema
import pytest
from addict import Dict
from faker import Faker
from flask import Response
from flask.testing import FlaskClient
from sqlalchemy.orm import sessionmaker

from app import db as db_
from app import app
from app import app, User, BlogPost, BlogComment, Log
from faker import Faker

Session = sessionmaker()

fake = Faker()

with open('tests/jsonapi_schema.json', 'r') as f:
api_schema = json.load(f)


@pytest.yield_fixture(scope='session')
def flask_app():
Expand Down Expand Up @@ -63,9 +57,7 @@ def validate(self, status_code, error=None):
assert self.status_code == status_code
assert self.headers['Content-Type'] == 'application/vnd.api+json'
if status_code != 204:
json_data = json.loads(self.data.decode())
jsonschema.validate(json_data, api_schema)
self.json_data = Dict(json_data)
self.json_data = json.loads(self.data.decode())
if error:
assert self.status_code == error.status_code
assert self.json_data['errors'][0]['code'] == error.code
Expand All @@ -77,7 +69,68 @@ def validate(self, status_code, error=None):
@pytest.fixture
def client(flask_app):
"""Set up the testing client."""
with FlaskClient(
flask_app, use_cookies=True,
response_wrapper=TestingResponse) as c:
with FlaskClient(flask_app,
use_cookies=True,
response_wrapper=TestingResponse) as c:
return c


@pytest.fixture
def user(session):
new_user = User(email=fake.email(),
password=fake.sentence(),
username=fake.user_name())
session.add(new_user)
session.commit()
return new_user


@pytest.fixture
def post(user, session):
new_post = BlogPost(author=user,
title=fake.sentence(),
content=fake.paragraph(),
is_published=True)
session.add(new_post)
session.commit()
return new_post


@pytest.fixture
def unpublished_post(user, session):
new_post = BlogPost(author=user,
title=fake.sentence(),
content=fake.paragraph(),
is_published=False)
session.add(new_post)
session.commit()
return new_post


@pytest.fixture
def bunch_of_posts(user, session):
for x in range(30):
new_post = BlogPost(author=user,
title=fake.sentence(),
content=fake.paragraph(),
is_published=fake.boolean())
session.add(new_post)
new_post.comments.append(BlogComment(author=user,
content=fake.paragraph()))
session.commit()


@pytest.fixture
def comment(user, post, session):
new_comment = BlogComment(author=user, post=post, content=fake.paragraph())
session.add(new_comment)
session.commit()
return new_comment


@pytest.fixture
def log(user, post, session):
new_log = Log(user=user, post=post)
session.add(new_log)
session.commit()
return new_log
Loading

0 comments on commit 5461eed

Please sign in to comment.