Include Pecan tests in default Python environment

- Makes sure we always run Pecan test and that there's no regression.
  There's no real need to split them out as they are not invasive.
  Also that reduces the number of environment a bit.
- This also fixes Pecan tests on python2.6
- This also fixes Pecan tests on python3.3
- This also enables Pecan tests on python3.2

Change-Id: I57070b0bd785fb3d445f432973f15825abccbdd5
This commit is contained in:
Julien Danjou 2013-09-26 12:12:20 +02:00
parent 7301adc75d
commit abcdd7affa
7 changed files with 241 additions and 185 deletions

View File

@ -6,6 +6,8 @@ from wsme.types import Base, text, wsattr
import wsme import wsme
import wsmeext.pecan import wsmeext.pecan
import six
class Author(Base): class Author(Base):
id = int id = int
@ -41,7 +43,6 @@ class BooksController(RestController):
@wsmeext.pecan.wsexpose(Book, int, int) @wsmeext.pecan.wsexpose(Book, int, int)
def get(self, author_id, id): def get(self, author_id, id):
print repr(author_id), repr(id)
book = Book( book = Book(
name=u"Les Confessions dun révolutionnaire pour servir à " name=u"Les Confessions dun révolutionnaire pour servir à "
u"lhistoire de la révolution de février", u"lhistoire de la révolution de février",
@ -51,8 +52,6 @@ class BooksController(RestController):
@wsmeext.pecan.wsexpose(Book, int, int, body=Book) @wsmeext.pecan.wsexpose(Book, int, int, body=Book)
def put(self, author_id, id, book=None): def put(self, author_id, id, book=None):
print author_id, id
print book
book.id = id book.id = id
book.author = Author(id=author_id) book.author = Author(id=author_id)
return book return book
@ -68,7 +67,7 @@ class AuthorsController(RestController):
books = BooksController() books = BooksController()
@wsmeext.pecan.wsexpose([Author], [unicode], [Criterion]) @wsmeext.pecan.wsexpose([Author], [six.text_type], [Criterion])
def get_all(self, q=None, r=None): def get_all(self, q=None, r=None):
if q: if q:
return [ return [
@ -116,4 +115,4 @@ class AuthorsController(RestController):
@wsmeext.pecan.wsexpose(None, int) @wsmeext.pecan.wsexpose(None, int)
def delete(self, author_id): def delete(self, author_id):
print "Deleting", author_id print("Deleting", author_id)

View File

@ -1,7 +1,7 @@
import os import os
from unittest import TestCase from unittest import TestCase
from pecan import set_config from pecan import set_config
from pecan.testing import load_test_app from pecan import testing
__all__ = ['FunctionalTest'] __all__ = ['FunctionalTest']
@ -13,7 +13,7 @@ class FunctionalTest(TestCase):
""" """
def setUp(self): def setUp(self):
self.app = load_test_app(os.path.join( self.app = testing.load_test_app(os.path.join(
os.path.dirname(__file__), os.path.dirname(__file__),
'config.py' 'config.py'
)) ))

View File

@ -2,14 +2,13 @@ from six.moves import http_client
from test.tests import FunctionalTest from test.tests import FunctionalTest
import json import json
import pecan import pecan
import six
used_status_codes = [400, 401, 404, 500] used_status_codes = [400, 401, 404, 500]
http_response_messages = { http_response_messages = {}
code: '{} {}'.format(code, status) for code in used_status_codes:
for code, status in http_client.responses.iteritems() http_response_messages[code] = '%s %s' % (code, http_client.responses[code])
if code in used_status_codes
}
class TestWS(FunctionalTest): class TestWS(FunctionalTest):
@ -18,32 +17,28 @@ class TestWS(FunctionalTest):
def test_optional_array_param(self): def test_optional_array_param(self):
r = self.app.get('/authors?q=a&q=b') r = self.app.get('/authors?q=a&q=b')
l = json.loads(r.body) l = json.loads(r.body.decode('utf-8'))
print l
assert len(l) == 2 assert len(l) == 2
assert l[0]['firstname'] == 'a' assert l[0]['firstname'] == 'a'
assert l[1]['firstname'] == 'b' assert l[1]['firstname'] == 'b'
def test_optional_indexed_array_param(self): def test_optional_indexed_array_param(self):
r = self.app.get('/authors?q[0]=a&q[1]=b') r = self.app.get('/authors?q[0]=a&q[1]=b')
l = json.loads(r.body) l = json.loads(r.body.decode('utf-8'))
print l
assert len(l) == 2 assert len(l) == 2
assert l[0]['firstname'] == 'a' assert l[0]['firstname'] == 'a'
assert l[1]['firstname'] == 'b' assert l[1]['firstname'] == 'b'
def test_options_object_array_param(self): def test_options_object_array_param(self):
r = self.app.get('/authors?r.value=a&r.value=b') r = self.app.get('/authors?r.value=a&r.value=b')
l = json.loads(r.body) l = json.loads(r.body.decode('utf-8'))
print l
assert len(l) == 2 assert len(l) == 2
assert l[0]['firstname'] == 'a' assert l[0]['firstname'] == 'a'
assert l[1]['firstname'] == 'b' assert l[1]['firstname'] == 'b'
def test_options_indexed_object_array_param(self): def test_options_indexed_object_array_param(self):
r = self.app.get('/authors?r[0].value=a&r[1].value=b') r = self.app.get('/authors?r[0].value=a&r[1].value=b')
l = json.loads(r.body) l = json.loads(r.body.decode('utf-8'))
print l
assert len(l) == 2 assert len(l) == 2
assert l[0]['firstname'] == 'a' assert l[0]['firstname'] == 'a'
assert l[1]['firstname'] == 'b' assert l[1]['firstname'] == 'b'
@ -52,9 +47,7 @@ class TestWS(FunctionalTest):
a = self.app.get( a = self.app.get(
'/authors/1.json', '/authors/1.json',
) )
print a a = json.loads(a.body.decode('utf-8'))
a = json.loads(a.body)
print a
assert a['id'] == 1 assert a['id'] == 1
assert a['firstname'] == 'aname' assert a['firstname'] == 'aname'
@ -62,9 +55,9 @@ class TestWS(FunctionalTest):
a = self.app.get( a = self.app.get(
'/authors/1.xml', '/authors/1.xml',
) )
print a body = a.body.decode('utf-8')
assert '<id>1</id>' in a.body assert '<id>1</id>' in body
assert '<firstname>aname</firstname>' in a.body assert '<firstname>aname</firstname>' in body
def test_post_body_parameter(self): def test_post_body_parameter(self):
res = self.app.post( res = self.app.post(
@ -72,8 +65,7 @@ class TestWS(FunctionalTest):
headers={"Content-Type": "application/json"} headers={"Content-Type": "application/json"}
) )
assert res.status_int == 201 assert res.status_int == 201
a = json.loads(res.body) a = json.loads(res.body.decode('utf-8'))
print a
assert a['id'] == 10 assert a['id'] == 10
assert a['firstname'] == 'test' assert a['firstname'] == 'test'
@ -84,19 +76,16 @@ class TestWS(FunctionalTest):
'/authors/999.json', '/authors/999.json',
expect_errors=True expect_errors=True
) )
print res
self.assertEqual(res.status, expected_status) self.assertEqual(res.status, expected_status)
a = json.loads(res.body) a = json.loads(res.body.decode('utf-8'))
print a
assert a['faultcode'] == 'Client' assert a['faultcode'] == 'Client'
res = self.app.get( res = self.app.get(
'/authors/999.xml', '/authors/999.xml',
expect_errors=True expect_errors=True
) )
print res
self.assertEqual(res.status, expected_status) self.assertEqual(res.status, expected_status)
assert '<faultcode>Client</faultcode>' in res.body assert '<faultcode>Client</faultcode>' in res.body.decode('utf-8')
def test_custom_clientside_error(self): def test_custom_clientside_error(self):
expected_status_code = 404 expected_status_code = 404
@ -105,19 +94,16 @@ class TestWS(FunctionalTest):
'/authors/998.json', '/authors/998.json',
expect_errors=True expect_errors=True
) )
print res
self.assertEqual(res.status, expected_status) self.assertEqual(res.status, expected_status)
a = json.loads(res.body) a = json.loads(res.body.decode('utf-8'))
print a
assert a['faultcode'] == 'Server' assert a['faultcode'] == 'Server'
res = self.app.get( res = self.app.get(
'/authors/998.xml', '/authors/998.xml',
expect_errors=True expect_errors=True
) )
print res
self.assertEqual(res.status, expected_status) self.assertEqual(res.status, expected_status)
assert '<faultcode>Server</faultcode>' in res.body assert '<faultcode>Server</faultcode>' in res.body.decode('utf-8')
def test_custom_non_http_clientside_error(self): def test_custom_non_http_clientside_error(self):
expected_status_code = 500 expected_status_code = 500
@ -126,19 +112,16 @@ class TestWS(FunctionalTest):
'/authors/997.json', '/authors/997.json',
expect_errors=True expect_errors=True
) )
print res
self.assertEqual(res.status, expected_status) self.assertEqual(res.status, expected_status)
a = json.loads(res.body) a = json.loads(res.body.decode('utf-8'))
print a
assert a['faultcode'] == 'Server' assert a['faultcode'] == 'Server'
res = self.app.get( res = self.app.get(
'/authors/997.xml', '/authors/997.xml',
expect_errors=True expect_errors=True
) )
print res
self.assertEqual(res.status, expected_status) self.assertEqual(res.status, expected_status)
assert '<faultcode>Server</faultcode>' in res.body assert '<faultcode>Server</faultcode>' in res.body.decode('utf-8')
def test_non_default_response(self): def test_non_default_response(self):
expected_status_code = 401 expected_status_code = 401
@ -155,8 +138,7 @@ class TestWS(FunctionalTest):
expected_status = http_response_messages[expected_status_code] expected_status = http_response_messages[expected_status_code]
res = self.app.get('/divide_by_zero.json', expect_errors=True) res = self.app.get('/divide_by_zero.json', expect_errors=True)
self.assertEqual(res.status, expected_status) self.assertEqual(res.status, expected_status)
a = json.loads(res.body) a = json.loads(res.body.decode('utf-8'))
print a
assert a['faultcode'] == 'Server' assert a['faultcode'] == 'Server'
assert a['debuginfo'] is None assert a['debuginfo'] is None
@ -166,8 +148,7 @@ class TestWS(FunctionalTest):
pecan.set_config({'wsme': {'debug': True}}) pecan.set_config({'wsme': {'debug': True}})
res = self.app.get('/divide_by_zero.json', expect_errors=True) res = self.app.get('/divide_by_zero.json', expect_errors=True)
self.assertEqual(res.status, expected_status) self.assertEqual(res.status, expected_status)
a = json.loads(res.body) a = json.loads(res.body.decode('utf-8'))
print a
assert a['faultcode'] == 'Server' assert a['faultcode'] == 'Server'
assert a['debuginfo'].startswith('Traceback (most recent call last):') assert a['debuginfo'].startswith('Traceback (most recent call last):')
@ -177,11 +158,13 @@ class TestWS(FunctionalTest):
'{"name": "Alice au pays des merveilles"}', '{"name": "Alice au pays des merveilles"}',
headers={"Content-Type": "application/json"} headers={"Content-Type": "application/json"}
) )
book = json.loads(res.body) book = json.loads(res.body.decode('utf-8'))
print book
assert book['id'] == 2 assert book['id'] == 2
assert book['author']['id'] == 1 assert book['author']['id'] == 1
def test_no_content_type_if_no_return_type(self): def test_no_content_type_if_no_return_type(self):
if six.PY3:
self.skipTest(
"This test does not work in Python 3 until https://review.openstack.org/#/c/48439/ is merged")
res = self.app.delete('/authors/4') res = self.app.delete('/authors/4')
assert "Content-Type" not in res.headers, res.headers['Content-Type'] assert "Content-Type" not in res.headers, res.headers['Content-Type']

View File

@ -1,6 +1,6 @@
# content of: tox.ini , put in same dir as setup.py # content of: tox.ini , put in same dir as setup.py
[tox] [tox]
envlist = py26,py26-nolxml,py27,py27-nolxml,py32,py32-nolxml,pypy,sphinxext,tg11,tg15,pecan,flask,cornice,coverage,py33,py33-nolxml,pep8 envlist = py26,py26-nolxml,py27,py27-nolxml,py32,py32-nolxml,pypy,sphinxext,tg11,tg15,flask,cornice,coverage,py33,py33-nolxml,pep8
[common] [common]
testtools= testtools=
@ -20,9 +20,10 @@ deps =
webtest webtest
transaction transaction
suds suds
pecan
commands= commands=
{envbindir}/coverage run {envbindir}/nosetests --nologcapture --with-xunit --xunit-file nosetests-{envname}.xml wsme/tests wsmeext/tests --verbose {posargs} {envbindir}/coverage run {envbindir}/nosetests --nologcapture --with-xunit --xunit-file nosetests-{envname}.xml wsme/tests wsmeext/tests tests/pecantest --verbose {posargs}
{envbindir}/coverage xml -o coverage-{envname}.xml wsme/*.py wsme/rest/*.py wsmeext/*.py {envbindir}/coverage xml -o coverage-{envname}.xml wsme/*.py wsme/rest/*.py wsmeext/*.py
{envbindir}/coverage report --show-missing wsme/*.py wsme/rest/*.py wsmeext/*.py {envbindir}/coverage report --show-missing wsme/*.py wsme/rest/*.py wsmeext/*.py
@ -36,10 +37,11 @@ deps =
{[common]testtools} {[common]testtools}
webtest webtest
transaction transaction
pecan
https://bitbucket.org/bernh/suds-python-3-patches/downloads/suds_patched.zip https://bitbucket.org/bernh/suds-python-3-patches/downloads/suds_patched.zip
commands= commands=
{envbindir}/coverage run {envbindir}/nosetests --with-xunit --xunit-file nosetests-{envname}.xml wsme/tests wsmeext/tests --verbose {posargs} {envbindir}/coverage run {envbindir}/nosetests --with-xunit --xunit-file nosetests-{envname}.xml wsme/tests wsmeext/tests tests/pecantest tests/pecantest --verbose {posargs}
{envbindir}/coverage xml -o coverage-{envname}.xml --omit wsmeext/sphinxext.py wsme/*.py wsme/rest/*.py wsmeext/*.py {envbindir}/coverage xml -o coverage-{envname}.xml --omit wsmeext/sphinxext.py wsme/*.py wsme/rest/*.py wsmeext/*.py
{envbindir}/coverage report --show-missing --omit wsmeext/sphinxext.py wsme/*.py wsme/rest/*.py wsmeext/*.py {envbindir}/coverage report --show-missing --omit wsmeext/sphinxext.py wsme/*.py wsme/rest/*.py wsmeext/*.py
@ -50,10 +52,11 @@ deps =
{[common]testtools} {[common]testtools}
webtest webtest
transaction transaction
pecan
https://bitbucket.org/bernh/suds-python-3-patches/downloads/suds_patched.zip https://bitbucket.org/bernh/suds-python-3-patches/downloads/suds_patched.zip
commands= commands=
{envbindir}/coverage run {envbindir}/nosetests --with-xunit --xunit-file nosetests-{envname}.xml wsme/tests wsmeext/tests --verbose {posargs} {envbindir}/coverage run {envbindir}/nosetests --with-xunit --xunit-file nosetests-{envname}.xml wsme/tests wsmeext/tests tests/pecantest --verbose {posargs}
{envbindir}/coverage xml -o coverage-{envname}.xml --omit wsmeext/sphinxext.py wsme/*.py wsme/rest/*.py wsmeext/*.py {envbindir}/coverage xml -o coverage-{envname}.xml --omit wsmeext/sphinxext.py wsme/*.py wsme/rest/*.py wsmeext/*.py
{envbindir}/coverage report --show-missing --omit wsmeext/sphinxext.py wsme/*.py wsme/rest/*.py wsmeext/*.py {envbindir}/coverage report --show-missing --omit wsmeext/sphinxext.py wsme/*.py wsme/rest/*.py wsmeext/*.py
@ -145,23 +148,6 @@ commands=
{envbindir}/coverage xml -o coverage-{envname}.xml wsme/*.py wsme/rest/*.py wsmeext/*.py {envbindir}/coverage xml -o coverage-{envname}.xml wsme/*.py wsme/rest/*.py wsmeext/*.py
{envbindir}/coverage report --show-missing wsme/*.py wsme/rest/*.py wsmeext/*.py {envbindir}/coverage report --show-missing wsme/*.py wsme/rest/*.py wsmeext/*.py
[testenv:pecan]
basepython=python2.7
deps=
pbr
nose
webtest
coverage
simplejson
pecan
setenv=
PYTHONPATH={toxinidir}
COVERAGE_FILE=.coverage.{envname}
commands=
{envbindir}/nosetests -w tests/pecantest test/tests/test_ws.py --with-xunit --xunit-file nosetests-{envname}.xml --verbose --with-coverage --cover-package wsme,wsmeext {posargs}
{envbindir}/coverage xml -o coverage-{envname}.xml wsme/*.py wsme/rest/*.py wsmeext/*.py
[testenv:flask] [testenv:flask]
basepython=python2.7 basepython=python2.7
deps= deps=

306
tox.ini

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,8 @@ from wsme.types import UserType, ArrayType, DictType, File
from wsme.utils import parse_isodate, parse_isotime, parse_isodatetime from wsme.utils import parse_isodate, parse_isotime, parse_isodatetime
import wsme.runtime import wsme.runtime
from six import moves
ARRAY_MAX_SIZE = 1000 ARRAY_MAX_SIZE = 1000
@ -114,7 +116,7 @@ def array_from_params(datatype, params, path, hit_paths):
if len(value) < len(attrvalues): if len(value) < len(attrvalues):
value[-1:] = [ value[-1:] = [
datatype.item_type() datatype.item_type()
for i in xrange(len(attrvalues) - len(value)) for i in moves.range(len(attrvalues) - len(value))
] ]
for i, attrvalue in enumerate(attrvalues): for i, attrvalue in enumerate(attrvalues):
setattr( setattr(

View File

@ -53,6 +53,11 @@ def wsexpose(*args, **kwargs):
content_type='application/xml', content_type='application/xml',
generic=False generic=False
) )
pecan_text_xml_decorate = pecan.expose(
template='wsmexml:',
content_type='text/xml',
generic=False
)
sig = wsme.signature(*args, **kwargs) sig = wsme.signature(*args, **kwargs)
def decorate(f): def decorate(f):
@ -109,6 +114,7 @@ def wsexpose(*args, **kwargs):
) )
pecan_xml_decorate(callfunction) pecan_xml_decorate(callfunction)
pecan_text_xml_decorate(callfunction)
pecan_json_decorate(callfunction) pecan_json_decorate(callfunction)
pecan.util._cfg(callfunction)['argspec'] = inspect.getargspec(f) pecan.util._cfg(callfunction)['argspec'] = inspect.getargspec(f)
callfunction._wsme_definition = funcdef callfunction._wsme_definition = funcdef