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
|
||||
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
|
||||
crack open refstack.cfg in your preffered editor.
|
||||
`vim refstack.cfg`
|
||||
|
||||
Now browse to http://localhost:8000
|
||||
Now available http://localhost:8000/ with JSON response {'Root': 'OK'}
|
||||
and http://localhost:8000/v1/results/ with JSON response {'Results': 'OK'}.
|
||||
|
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) 2014 Piston Cloud Computing, Inc. All Rights Reserved.
|
||||
# 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
|
||||
@ -12,15 +12,16 @@
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
import unittest
|
||||
|
||||
from pecan import make_app
|
||||
|
||||
|
||||
class TestSequenceFunctions(unittest.TestCase):
|
||||
def setup_app(config):
|
||||
|
||||
def test_nothing(self):
|
||||
# make sure the shuffled sequence does not lose any elements
|
||||
pass
|
||||
app_conf = dict(config.app)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
return make_app(
|
||||
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
|
||||
alembic==0.5.0
|
||||
gunicorn==0.17.4
|
||||
pecan>=0.8.2
|
||||
pyOpenSSL==0.13
|
||||
pycrypto==2.6
|
||||
requests==1.2.3
|
||||
|
Loading…
Reference in New Issue
Block a user