added NewsSource routes with tests

master
androiddrew 8 years ago
parent 095ef0b1db
commit a02d696f9f

@ -1,19 +1,76 @@
from apistar import Include, Route
from apistar import Include, Route, http
from apistar.interfaces import Router
from apistar.frameworks.wsgi import WSGIApp as App
from apistar.backends import sqlalchemy_backend
from apistar.backends.sqlalchemy_backend import Session
from apistar.handlers import docs_urls, static_urls
from .models import Base
from .models import Base, NewsArticle, NewsSource
from .renders import JSONRenderer
from .schema import NewsSourceSchema
news_source_schema = NewsSourceSchema()
def welcome():
return {"message": "welcome to news"}
def get_sources(session: Session):
sources = session.query(NewsSource).all()
return news_source_schema.dump(sources, many=True).data
def add_source(session: Session, request_data: http.RequestData, router: Router):
news_source_data, errors = news_source_schema.load(request_data)
if errors:
msg = {"message": "400 Bad Request", "error": errors}
return http.Response(msg, status=400)
news_source = NewsSource(**news_source_data)
session.add(news_source)
session.flush()
headers = {"Location": router.reverse_url('get_source', {"id": news_source.id})}
return http.Response(news_source_schema.dump(news_source).data, status=201, headers=headers)
def delete_source(session: Session, id: int):
"""Delete a single News Sources from the collection by id"""
news_source = session.query(NewsSource).filter_by(id=id).one_or_none()
if news_source is None:
msg = {"message": "404 Not Found"}
return http.Response(msg, status=404)
msg = {"message": "200 OK"}
return http.Response(msg, status=200)
def get_source(session: Session, id: int):
news_source = session.query(NewsSource).filter_by(id=id).one_or_none()
if news_source is None:
msg = {"message": "404 Not Found"}
return http.Response(msg, status=404)
return http.Response(news_source_schema.dump(news_source).data, status=200)
def get_articles(session: Session):
articles = session.query(NewsArticle).all()
return [article.to_dict() for article in articles]
def add_article(session: Session):
pass
def delete_article(session: Session):
pass
routes = [
Route('/', 'GET', welcome),
Route('/sources', 'GET', get_sources),
Route('/sources', 'POST', add_source),
Route('/sources/{id}', 'GET', get_source),
Route('/sources/{id}', 'DELETE', delete_source),
Route('/articles', 'GET', get_articles),
Include('/docs', docs_urls),
Include('/static', static_urls)
]
@ -26,7 +83,6 @@ _settings = {
'RENDERERS': [JSONRenderer()]
}
routes = routes
commands = sqlalchemy_backend.commands

@ -9,7 +9,7 @@ from apistar.renderers import Renderer
def extended_encoder(obj):
"""JSON encoder function with support for ISO 8601 datetime serialization and Decimal to float casting"""
if isinstance(obj, dt.datetime):
return obj.isoformat()
return obj.timestamp()
elif isinstance(obj, decimal.Decimal):
return float(obj)

@ -0,0 +1,13 @@
from marshmallow import Schema, fields
class NewsSourceSchema(Schema):
id = fields.Int(dump_only=True)
created_date = fields.DateTime(dump_only=True)
modified_date = fields.DateTime()
url = fields.URL()
source_name = fields.Str(required=True, error_messages={'required': 'NewsSource name is a required field'})
source_type = fields.Str(required=True, error_messages={'required': 'NewsSource tyoe is a required field'})
class Meta:
ordered = True

@ -9,8 +9,7 @@ from news.app import commands, routes, components
settings = {
'DATABASE': {
'URL': 'postgresql://apistar:local@localhost/news',
#'URL': 'sqlite:///',
'URL': 'postgresql://apistar:local@localhost/testnews',
'METADATA': Base.metadata
},
'RENDERERS': [JSONRenderer()],

@ -1,5 +1,143 @@
from news.app import welcome
import datetime as dt
from unittest import mock
def test_welcome_route():
message = {"message": "welcome to news"}
assert message == welcome()
import pytest
from news.app import get_articles, get_sources, add_source, get_source, delete_source
from news.models import NewsArticle, NewsSource, Category, Tag
# Sources
def test_get_empty__news_sources(rb_session):
assert [] == get_sources(rb_session)
def test_get_news_sources(rb_session):
test_source = NewsSource(url='http://money.test.com',
source_name='TEST',
source_type='website',
categories=[Category(category_name='finance')]
)
rb_session.add(test_source)
rb_session.flush()
assert 1 == len(get_sources(rb_session))
def test_add_news_source(rb_session):
test_source = {
'source_name': 'TEST',
'source_type': 'website',
'url': 'http://money.test.com'
}
mock_router = mock.Mock()
mock_router.configure_mock(
**{"reverse_url.return_value": "/mylocation"}
)
result = add_source(rb_session, test_source, mock_router)
assert 201 == result.status
assert 'location' in result.headers.keys()
def test_add_news_source_error(rb_session):
"""Testing with missing required field"""
test_source = {
'source_type': 'website',
'url': 'http://money.test.com'
}
mock_router = mock.Mock()
mock_router.configure_mock(
**{"reverse_url.return_value": "/mylocation"}
)
result = add_source(rb_session, test_source, mock_router)
print(result.headers)
assert 400 == result.status
def test_get_news_source(rb_session):
test_source = NewsSource(url='http://money.test.com',
source_name='TEST',
source_type='website',
categories=[Category(category_name='finance')]
)
rb_session.add(test_source)
rb_session.flush()
result = get_source(rb_session, 1)
assert 200 == result.status
def test_get_news_source_404_error(rb_session):
test_source = NewsSource(url='http://money.test.com',
source_name='TEST',
source_type='website',
categories=[Category(category_name='finance')]
)
rb_session.add(test_source)
rb_session.flush()
result = get_source(rb_session, 2)
assert 404 == result.status
def test_delete_news_source(rb_session):
test_source = NewsSource(url='http://money.test.com',
source_name='TEST',
source_type='website',
categories=[Category(category_name='finance')]
)
rb_session.add(test_source)
rb_session.flush()
result = delete_source(rb_session, 1)
assert 200 == result.status
def test_delete_news_source_404(rb_session):
test_source = NewsSource(url='http://money.test.com',
source_name='TEST',
source_type='website',
categories=[Category(category_name='finance')]
)
rb_session.add(test_source)
rb_session.flush()
result = delete_source(rb_session, 2)
assert 404 == result.status
# Articles
def test_get_empty_articles(rb_session):
assert get_articles(rb_session) == []
def test_get_articles(rb_session):
source = NewsSource(url='http://money.test.com',
source_name='TEST',
source_type='website',
categories=[Category(category_name='finance')]
)
article = NewsArticle(url='http://money.test.com/article',
title='article',
authors=['drew', 'jesse'],
publish_date=dt.datetime.utcnow(),
news_blob='article content',
news_source=source,
tags=[Tag(tag_name='article')]
)
rb_session.add(article)
rb_session.flush()
assert 1 == len(get_articles(rb_session))

@ -7,7 +7,7 @@ from news.renders import extended_encoder, JSONRenderer
def test_extended_encoder_date_parsing():
test_date = dt.datetime(2017, 5, 10)
assert test_date.isoformat() == extended_encoder(test_date)
assert test_date.timestamp() == extended_encoder(test_date)
def test_extended_encoder_decimal_casting():
@ -18,6 +18,6 @@ def test_extended_encoder_decimal_casting():
def test_render_with_extended_encoder():
test_date = dt.datetime(2017, 5, 10)
test_decimal = Decimal('0.1')
expected = dict(my_date="2017-05-10T00:00:00", my_float=0.1)
expected = dict(my_date=1494388800.0, my_float=0.1)
test_response = dict(my_date=test_date, my_float=test_decimal)
assert json.dumps(expected).encode('utf-8') == JSONRenderer().render(test_response)
Loading…
Cancel
Save