Add API prototype on Pecan
Add API prototype on Pecan. Add functioanal tests. Update documentation for running new API. Delete old API and unit tests for it. Change-Id: I42b3539d8420b2b5edf44d5265654b738e7ffa5e
This commit is contained in:
parent
a11dcb8487
commit
c76114ea23
@ -38,10 +38,7 @@ We use nginx and gunicorn, you may use something else if you so desire.
|
|||||||
For the most basic setup that you can try right now, just kick off
|
For the most basic setup that you can try right now, just kick off
|
||||||
gunicorn:
|
gunicorn:
|
||||||
|
|
||||||
`gunicorn -b 0.0.0.0:8000 refstack.web:app`
|
`gunicorn_pecan refstack/api/config.py`
|
||||||
|
|
||||||
To actually configure refstack, check out the config section and
|
Now available http://localhost:8000/ with JSON response {'Root': 'OK'}
|
||||||
crack open refstack.cfg in your preffered editor.
|
and http://localhost:8000/v1/results/ with JSON response {'Results': 'OK'}.
|
||||||
`vim refstack.cfg`
|
|
||||||
|
|
||||||
Now browse to http://localhost:8000
|
|
||||||
|
0
refstack/api/__init__.py
Normal file
0
refstack/api/__init__.py
Normal file
21
refstack/tests/unit/tests.py → refstack/api/app.py
Executable file → Normal file
21
refstack/tests/unit/tests.py → refstack/api/app.py
Executable file → Normal file
@ -1,5 +1,5 @@
|
|||||||
#
|
# Copyright (c) 2015 Mirantis, Inc.
|
||||||
# Copyright (c) 2014 Piston Cloud Computing, Inc. All Rights Reserved.
|
# All Rights Reserved.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
# not use this file except in compliance with the License. You may obtain
|
# not use this file except in compliance with the License. You may obtain
|
||||||
@ -12,15 +12,16 @@
|
|||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
#
|
|
||||||
import unittest
|
from pecan import make_app
|
||||||
|
|
||||||
|
|
||||||
class TestSequenceFunctions(unittest.TestCase):
|
def setup_app(config):
|
||||||
|
|
||||||
def test_nothing(self):
|
app_conf = dict(config.app)
|
||||||
# make sure the shuffled sequence does not lose any elements
|
|
||||||
pass
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
return make_app(
|
||||||
unittest.main()
|
app_conf.pop('root'),
|
||||||
|
logging=getattr(config, 'logging', {}),
|
||||||
|
**app_conf
|
||||||
|
)
|
63
refstack/api/config.py
Normal file
63
refstack/api/config.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
# Copyright (c) 2015 Mirantis, Inc.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
"""Configuration for running API.
|
||||||
|
|
||||||
|
Custom Configurations must be in Python dictionary format:
|
||||||
|
|
||||||
|
foo = {'bar':'baz'}
|
||||||
|
|
||||||
|
All configurations are accessible at:
|
||||||
|
pecan.conf
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Server Specific Configurations
|
||||||
|
server = {
|
||||||
|
'port': '8000',
|
||||||
|
'host': '0.0.0.0'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Pecan Application Configurations
|
||||||
|
app = {
|
||||||
|
'root': 'refstack.api.controllers.root.RootController',
|
||||||
|
'modules': ['refstack.api'],
|
||||||
|
'static_root': '%(confdir)s/public',
|
||||||
|
'template_path': '%(confdir)s/${package}/templates',
|
||||||
|
'debug': False,
|
||||||
|
'errors': {
|
||||||
|
'404': '/error/404',
|
||||||
|
'__force_dict__': True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logging = {
|
||||||
|
'loggers': {
|
||||||
|
'root': {'level': 'INFO', 'handlers': ['console']},
|
||||||
|
'refstack': {'level': 'DEBUG', 'handlers': ['console']}
|
||||||
|
},
|
||||||
|
'handlers': {
|
||||||
|
'console': {
|
||||||
|
'level': 'DEBUG',
|
||||||
|
'class': 'logging.StreamHandler',
|
||||||
|
'formatter': 'simple'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'formatters': {
|
||||||
|
'simple': {
|
||||||
|
'format': ('%(asctime)s %(levelname)-5.5s [%(name)s]'
|
||||||
|
'[%(threadName)s] %(message)s')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
0
refstack/api/controllers/__init__.py
Normal file
0
refstack/api/controllers/__init__.py
Normal file
28
refstack/api/controllers/root.py
Normal file
28
refstack/api/controllers/root.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Copyright (c) 2015 Mirantis, Inc.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from pecan import expose
|
||||||
|
|
||||||
|
from refstack.api.controllers import v1
|
||||||
|
|
||||||
|
|
||||||
|
class RootController(object):
|
||||||
|
|
||||||
|
v1 = v1.V1Controller()
|
||||||
|
|
||||||
|
@expose('json')
|
||||||
|
def index(self):
|
||||||
|
"""root response."""
|
||||||
|
return {'Root': 'OK'}
|
32
refstack/api/controllers/v1.py
Normal file
32
refstack/api/controllers/v1.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# Copyright (c) 2015 Mirantis, Inc.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
"""Version 1 of the API.
|
||||||
|
"""
|
||||||
|
from pecan import expose
|
||||||
|
from pecan import rest
|
||||||
|
|
||||||
|
|
||||||
|
class ResultsController(rest.RestController):
|
||||||
|
|
||||||
|
@expose('json')
|
||||||
|
def index(self):
|
||||||
|
return {'Results': 'OK'}
|
||||||
|
|
||||||
|
|
||||||
|
class V1Controller(object):
|
||||||
|
"""Version 1 API controller root."""
|
||||||
|
|
||||||
|
results = ResultsController()
|
72
refstack/tests/api/__init__.py
Normal file
72
refstack/tests/api/__init__.py
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
# Copyright (c) 2015 Mirantis, Inc.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
"""Base classes for API tests.
|
||||||
|
"""
|
||||||
|
from unittest import TestCase
|
||||||
|
from pecan import set_config
|
||||||
|
from pecan.testing import load_test_app
|
||||||
|
|
||||||
|
|
||||||
|
class FunctionalTest(TestCase):
|
||||||
|
"""
|
||||||
|
Used for functional tests where you need to test your
|
||||||
|
literal application and its integration with the framework.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.config = {
|
||||||
|
'app': {
|
||||||
|
'root': 'refstack.api.controllers.root.RootController',
|
||||||
|
'modules': ['refstack.api'],
|
||||||
|
'static_root': '%(confdir)s/public',
|
||||||
|
'template_path': '%(confdir)s/${package}/templates',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.app = load_test_app(self.config)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
set_config({}, overwrite=True)
|
||||||
|
|
||||||
|
def get_json(self, url, headers=None, extra_environ=None,
|
||||||
|
status=None, expect_errors=False, **params):
|
||||||
|
"""Sends HTTP GET request.
|
||||||
|
|
||||||
|
:param url: url path to target service
|
||||||
|
:param headers: a dictionary of extra headers to send
|
||||||
|
:param extra_environ: a dictionary of environmental variables that
|
||||||
|
should be added to the request
|
||||||
|
:param status: integer or string of the HTTP status code you expect
|
||||||
|
in response (if not 200 or 3xx). You can also use a
|
||||||
|
wildcard, like '3*' or '*'
|
||||||
|
:param expect_errors: boolean value, if this is False, then if
|
||||||
|
anything is written to environ wsgi.errors it
|
||||||
|
will be an error. If it is True, then
|
||||||
|
non-200/3xx responses are also okay
|
||||||
|
:param params: a query string, or a dictionary that will be encoded
|
||||||
|
into a query string. You may also include a URL query
|
||||||
|
string on the url
|
||||||
|
|
||||||
|
"""
|
||||||
|
response = self.app.get(url,
|
||||||
|
headers=headers,
|
||||||
|
extra_environ=extra_environ,
|
||||||
|
status=status,
|
||||||
|
expect_errors=expect_errors,
|
||||||
|
params=params)
|
||||||
|
|
||||||
|
if not expect_errors:
|
||||||
|
response = response.json
|
||||||
|
return response
|
29
refstack/tests/api/test_api.py
Normal file
29
refstack/tests/api/test_api.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# Copyright (c) 2015 Mirantis, Inc.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from refstack.tests import api
|
||||||
|
|
||||||
|
|
||||||
|
class TestRefStackApi(api.FunctionalTest):
|
||||||
|
|
||||||
|
def test_root_controller(self):
|
||||||
|
actual_response = self.get_json('/')
|
||||||
|
expected_response = {'Root': 'OK'}
|
||||||
|
self.assertEqual(expected_response, actual_response)
|
||||||
|
|
||||||
|
def test_results_controller(self):
|
||||||
|
actual_response = self.get_json('/v1/results/')
|
||||||
|
expected_response = {'Results': 'OK'}
|
||||||
|
self.assertEqual(expected_response, actual_response)
|
@ -1 +0,0 @@
|
|||||||
__author__ = 'dlenwell'
|
|
@ -1,6 +1,7 @@
|
|||||||
SQLAlchemy==0.8.3
|
SQLAlchemy==0.8.3
|
||||||
alembic==0.5.0
|
alembic==0.5.0
|
||||||
gunicorn==0.17.4
|
gunicorn==0.17.4
|
||||||
|
pecan>=0.8.2
|
||||||
pyOpenSSL==0.13
|
pyOpenSSL==0.13
|
||||||
pycrypto==2.6
|
pycrypto==2.6
|
||||||
requests==1.2.3
|
requests==1.2.3
|
||||||
|
Loading…
Reference in New Issue
Block a user