Add pecan transport driver and tests
This commit is contained in:
parent
7ced7423a2
commit
1737ae877d
29
cdn/manager/base/v1.py
Normal file
29
cdn/manager/base/v1.py
Normal file
@ -0,0 +1,29 @@
|
||||
# Copyright (c) 2014 Rackspace, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import abc
|
||||
import six
|
||||
|
||||
from cdn.manager.base import controller
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class V1ControllerBase(controller.ManagerControllerBase):
|
||||
def __init__(self, manager):
|
||||
super(V1ControllerBase, self).__init__(manager)
|
||||
|
||||
@abc.abstractmethod
|
||||
def get(self):
|
||||
raise NotImplementedError
|
31
cdn/manager/default/v1.py
Normal file
31
cdn/manager/default/v1.py
Normal file
@ -0,0 +1,31 @@
|
||||
from cdn.manager import base
|
||||
|
||||
JSON_HOME = {
|
||||
"resources": {
|
||||
"rel/cdn": {
|
||||
"href-template": "services{?marker,limit}",
|
||||
"href-vars": {
|
||||
"marker": "param/marker",
|
||||
"limit": "param/limit"
|
||||
},
|
||||
"hints": {
|
||||
"allow": [
|
||||
"GET"
|
||||
],
|
||||
"formats": {
|
||||
"application/json": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class DefaultV1Controller(base.V1Controller):
|
||||
def __init__(self, manager):
|
||||
super(DefaultV1Controller, self).__init__(manager)
|
||||
|
||||
self.JSON_HOME = JSON_HOME
|
||||
|
||||
def get(self):
|
||||
return self.JSON_HOME
|
126
cdn/openstack/common/context.py
Normal file
126
cdn/openstack/common/context.py
Normal file
@ -0,0 +1,126 @@
|
||||
# Copyright 2011 OpenStack Foundation.
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Simple class that stores security context information in the web request.
|
||||
|
||||
Projects should subclass this class if they wish to enhance the request
|
||||
context or provide additional information in their specific WSGI pipeline.
|
||||
"""
|
||||
|
||||
import itertools
|
||||
import uuid
|
||||
|
||||
|
||||
def generate_request_id():
|
||||
return b'req-' + str(uuid.uuid4()).encode('ascii')
|
||||
|
||||
|
||||
class RequestContext(object):
|
||||
|
||||
"""Helper class to represent useful information about a request context.
|
||||
|
||||
Stores information about the security context under which the user
|
||||
accesses the system, as well as additional request information.
|
||||
"""
|
||||
|
||||
user_idt_format = '{user} {tenant} {domain} {user_domain} {p_domain}'
|
||||
|
||||
def __init__(self, auth_token=None, user=None, tenant=None, domain=None,
|
||||
user_domain=None, project_domain=None, is_admin=False,
|
||||
read_only=False, show_deleted=False, request_id=None,
|
||||
instance_uuid=None):
|
||||
self.auth_token = auth_token
|
||||
self.user = user
|
||||
self.tenant = tenant
|
||||
self.domain = domain
|
||||
self.user_domain = user_domain
|
||||
self.project_domain = project_domain
|
||||
self.is_admin = is_admin
|
||||
self.read_only = read_only
|
||||
self.show_deleted = show_deleted
|
||||
self.instance_uuid = instance_uuid
|
||||
if not request_id:
|
||||
request_id = generate_request_id()
|
||||
self.request_id = request_id
|
||||
|
||||
def to_dict(self):
|
||||
user_idt = (
|
||||
self.user_idt_format.format(user=self.user or '-',
|
||||
tenant=self.tenant or '-',
|
||||
domain=self.domain or '-',
|
||||
user_domain=self.user_domain or '-',
|
||||
p_domain=self.project_domain or '-'))
|
||||
|
||||
return {'user': self.user,
|
||||
'tenant': self.tenant,
|
||||
'domain': self.domain,
|
||||
'user_domain': self.user_domain,
|
||||
'project_domain': self.project_domain,
|
||||
'is_admin': self.is_admin,
|
||||
'read_only': self.read_only,
|
||||
'show_deleted': self.show_deleted,
|
||||
'auth_token': self.auth_token,
|
||||
'request_id': self.request_id,
|
||||
'instance_uuid': self.instance_uuid,
|
||||
'user_identity': user_idt}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, ctx):
|
||||
return cls(
|
||||
auth_token=ctx.get("auth_token"),
|
||||
user=ctx.get("user"),
|
||||
tenant=ctx.get("tenant"),
|
||||
domain=ctx.get("domain"),
|
||||
user_domain=ctx.get("user_domain"),
|
||||
project_domain=ctx.get("project_domain"),
|
||||
is_admin=ctx.get("is_admin", False),
|
||||
read_only=ctx.get("read_only", False),
|
||||
show_deleted=ctx.get("show_deleted", False),
|
||||
request_id=ctx.get("request_id"),
|
||||
instance_uuid=ctx.get("instance_uuid"))
|
||||
|
||||
|
||||
def get_admin_context(show_deleted=False):
|
||||
context = RequestContext(None,
|
||||
tenant=None,
|
||||
is_admin=True,
|
||||
show_deleted=show_deleted)
|
||||
return context
|
||||
|
||||
|
||||
def get_context_from_function_and_args(function, args, kwargs):
|
||||
"""Find an arg of type RequestContext and return it.
|
||||
|
||||
This is useful in a couple of decorators where we don't
|
||||
know much about the function we're wrapping.
|
||||
"""
|
||||
|
||||
for arg in itertools.chain(kwargs.values(), args):
|
||||
if isinstance(arg, RequestContext):
|
||||
return arg
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def is_user_context(context):
|
||||
"""Indicates if the request context is a normal user."""
|
||||
if not context:
|
||||
return False
|
||||
if context.is_admin:
|
||||
return False
|
||||
if not context.user_id or not context.project_id:
|
||||
return False
|
||||
return True
|
37
cdn/transport/app.py
Normal file
37
cdn/transport/app.py
Normal file
@ -0,0 +1,37 @@
|
||||
# Copyright (c) 2014 Rackspace, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""WSGI callable for WSGI containers
|
||||
|
||||
This app should be used by external WSGI
|
||||
containers. For example:
|
||||
|
||||
$ gunicorn dory.transport.app:app
|
||||
|
||||
NOTE: As for external containers, it is necessary
|
||||
to put config files in the standard paths. There's
|
||||
no common way to specify / pass configuration files
|
||||
to the WSGI app when it is called from other apps.
|
||||
"""
|
||||
|
||||
from oslo.config import cfg
|
||||
|
||||
from dory import bootstrap
|
||||
|
||||
|
||||
conf = cfg.CONF
|
||||
conf(project='cdn', prog='cdn', args=[])
|
||||
|
||||
app = bootstrap.Bootstrap(conf).transport.app
|
22
cdn/transport/pecan/__init__.py
Normal file
22
cdn/transport/pecan/__init__.py
Normal file
@ -0,0 +1,22 @@
|
||||
# Copyright (c) 2014 Rackspace, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""Pecan Transport Driver"""
|
||||
|
||||
from cdn.transport.pecan import driver
|
||||
|
||||
|
||||
# Hoist into package namespace
|
||||
Driver = driver.PecanTransportDriver
|
26
cdn/transport/pecan/controllers/__init__.py
Normal file
26
cdn/transport/pecan/controllers/__init__.py
Normal file
@ -0,0 +1,26 @@
|
||||
# Copyright (c) 2014 Rackspace, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""Pecan Controllers"""
|
||||
|
||||
from cdn.transport.pecan.controllers import root
|
||||
from cdn.transport.pecan.controllers import services
|
||||
from cdn.transport.pecan.controllers import v1
|
||||
|
||||
|
||||
# Hoist into package namespace
|
||||
Root = root.RootController
|
||||
Services = services.ServicesController
|
||||
V1 = v1.V1Controller
|
25
cdn/transport/pecan/controllers/base.py
Normal file
25
cdn/transport/pecan/controllers/base.py
Normal file
@ -0,0 +1,25 @@
|
||||
# Copyright (c) 2014 Rackspace, Inc.
|
||||
#
|
||||
# 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 rest
|
||||
|
||||
|
||||
class Controller(rest.RestController):
|
||||
|
||||
def __init__(self, driver):
|
||||
self._driver = driver
|
||||
|
||||
def add_controller(self, path, controller):
|
||||
setattr(self, path, controller)
|
51
cdn/transport/pecan/controllers/root.py
Normal file
51
cdn/transport/pecan/controllers/root.py
Normal file
@ -0,0 +1,51 @@
|
||||
# Copyright (c) 2014 Rackspace, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import re
|
||||
|
||||
import pecan
|
||||
|
||||
from cdn.transport.pecan.controllers import base
|
||||
|
||||
|
||||
class RootController(base.Controller):
|
||||
|
||||
def __init__(self, driver):
|
||||
super(RootController, self).__init__(driver)
|
||||
self.paths = []
|
||||
|
||||
def add_controller(self, path, controller):
|
||||
super(RootController, self).add_controller(path, controller)
|
||||
self.paths.append(path)
|
||||
|
||||
@pecan.expose()
|
||||
def _route(self, args, request=None):
|
||||
# Optionally allow OpenStack project ID in the URL
|
||||
# Remove it from the URL if it's present
|
||||
# ['v1', 'todos'] or ['v1', '123', 'todos']
|
||||
if (
|
||||
len(args) >= 2
|
||||
and args[0] in self.paths
|
||||
and re.match('^[0-9]+$', args[1])
|
||||
):
|
||||
args.pop(1)
|
||||
|
||||
return super(RootController, self)._route(args, request)
|
||||
|
||||
@pecan.expose('json')
|
||||
def get_all(self):
|
||||
return {
|
||||
'status': 'up',
|
||||
}
|
35
cdn/transport/pecan/controllers/services.py
Normal file
35
cdn/transport/pecan/controllers/services.py
Normal file
@ -0,0 +1,35 @@
|
||||
# Copyright (c) 2014 Rackspace, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import uuid
|
||||
|
||||
import pecan
|
||||
|
||||
from cdn.transport.pecan.controllers import base
|
||||
|
||||
|
||||
class ServicesController(base.Controller):
|
||||
|
||||
@pecan.expose('json')
|
||||
def get_all(self):
|
||||
tenant_id = pecan.request.context.to_dict()['tenant']
|
||||
services_controller = self._driver.manager.services_controller
|
||||
return services_controller.list(tenant_id)
|
||||
|
||||
@pecan.expose('json')
|
||||
def get_one(self):
|
||||
tenant_id = pecan.request.context.to_dict()['tenant']
|
||||
services_controller = self._driver.manager.services_controller
|
||||
return services_controller.list(tenant_id)
|
26
cdn/transport/pecan/controllers/v1.py
Normal file
26
cdn/transport/pecan/controllers/v1.py
Normal file
@ -0,0 +1,26 @@
|
||||
# Copyright (c) 2014 Rackspace, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import pecan
|
||||
|
||||
from cdn.transport.pecan.controllers import base
|
||||
|
||||
|
||||
class V1Controller(base.Controller):
|
||||
|
||||
@pecan.expose('json')
|
||||
def get(self):
|
||||
v1_controller = self._driver.manager.v1_controller
|
||||
return v1_controller.get()
|
74
cdn/transport/pecan/driver.py
Normal file
74
cdn/transport/pecan/driver.py
Normal file
@ -0,0 +1,74 @@
|
||||
# Copyright (c) 2014 Rackspace, Inc.
|
||||
#
|
||||
# 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 wsgiref import simple_server
|
||||
|
||||
import pecan
|
||||
from oslo.config import cfg
|
||||
|
||||
from cdn.openstack.common import log
|
||||
from cdn import transport
|
||||
from cdn.transport.pecan import controllers
|
||||
from cdn.transport.pecan import hooks
|
||||
|
||||
|
||||
_PECAN_OPTIONS = [
|
||||
cfg.StrOpt('bind', default='127.0.0.1',
|
||||
help='Address on which the self-hosting server will listen'),
|
||||
cfg.IntOpt('port', default=8888,
|
||||
help='Port on which the self-hosting server will listen'),
|
||||
]
|
||||
|
||||
_PECAN_GROUP = 'drivers:transport:pecan'
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class PecanTransportDriver(transport.Driver):
|
||||
|
||||
def __init__(self, conf, manager):
|
||||
super(PecanTransportDriver, self).__init__(conf, manager)
|
||||
|
||||
self._conf.register_opts(_PECAN_OPTIONS, group=_PECAN_GROUP)
|
||||
self._pecan_conf = self._conf[_PECAN_GROUP]
|
||||
|
||||
self._setup_app()
|
||||
|
||||
def _setup_app(self):
|
||||
root_controller = controllers.Root(self)
|
||||
|
||||
pecan_hooks = [hooks.Context()]
|
||||
|
||||
self._app = pecan.make_app(root_controller, hooks=pecan_hooks)
|
||||
|
||||
v1_controller = controllers.V1(self)
|
||||
root_controller.add_controller('v1.0', v1_controller)
|
||||
|
||||
services_controller = controllers.Services(self)
|
||||
v1_controller.add_controller('services', services_controller)
|
||||
|
||||
def listen(self):
|
||||
LOG.info(
|
||||
'Serving on host %(bind)s:%(port)s',
|
||||
{
|
||||
'bind': self._pecan_conf.bind,
|
||||
'port': self._pecan_conf.port,
|
||||
},
|
||||
)
|
||||
|
||||
httpd = simple_server.make_server(self._pecan_conf.bind,
|
||||
self._pecan_conf.port,
|
||||
self.app)
|
||||
httpd.serve_forever()
|
22
cdn/transport/pecan/hooks/__init__.py
Normal file
22
cdn/transport/pecan/hooks/__init__.py
Normal file
@ -0,0 +1,22 @@
|
||||
# Copyright (c) 2014 Rackspace, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""Pecan Hooks"""
|
||||
|
||||
from cdn.transport.pecan.hooks import context
|
||||
|
||||
|
||||
# Hoist into package namespace
|
||||
Context = context.ContextHook
|
40
cdn/transport/pecan/hooks/context.py
Normal file
40
cdn/transport/pecan/hooks/context.py
Normal file
@ -0,0 +1,40 @@
|
||||
# Copyright (c) 2014 Rackspace, Inc.
|
||||
#
|
||||
# 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 hooks
|
||||
|
||||
from cdn.openstack.common import context
|
||||
from cdn.openstack.common import local
|
||||
|
||||
|
||||
class ContextHook(hooks.PecanHook):
|
||||
|
||||
def on_route(self, state):
|
||||
context_kwargs = {}
|
||||
|
||||
if 'X-Project-ID' in state.request.headers:
|
||||
context_kwargs['tenant'] = state.request.headers['X-Project-ID']
|
||||
|
||||
if 'tenant' not in context_kwargs:
|
||||
# Didn't find the X-Project-Id header, pull from URL instead
|
||||
# Expects form /v1/{project_id}/path
|
||||
context_kwargs['tenant'] = state.request.path.split('/')[2]
|
||||
|
||||
if 'X-Auth-Token' in state.request.headers:
|
||||
context_kwargs['auth_token'] = state.request.headers['X-Auth-Token']
|
||||
|
||||
request_context = context.RequestContext(**context_kwargs)
|
||||
state.request.context = request_context
|
||||
local.store.context = request_context
|
0
tests/functional/transport/pecan/__init__.py
Normal file
0
tests/functional/transport/pecan/__init__.py
Normal file
41
tests/functional/transport/pecan/base.py
Normal file
41
tests/functional/transport/pecan/base.py
Normal file
@ -0,0 +1,41 @@
|
||||
# Copyright (c) 2014 Rackspace, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import os
|
||||
|
||||
from oslo.config import cfg
|
||||
import testtools
|
||||
import webtest
|
||||
|
||||
from cdn import bootstrap
|
||||
|
||||
|
||||
class BaseFunctionalTest(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(BaseFunctionalTest, self).setUp()
|
||||
|
||||
tests_path = os.path.abspath(os.path.dirname(
|
||||
os.path.dirname(
|
||||
os.path.dirname(os.path.dirname(__file__)
|
||||
))))
|
||||
conf_path = os.path.join(tests_path, 'etc', 'default_functional.conf')
|
||||
cfg.CONF(args=[], default_config_files=[conf_path])
|
||||
cdn_wsgi = bootstrap.Bootstrap(cfg.CONF).transport.app
|
||||
|
||||
self.app = webtest.TestApp(cdn_wsgi)
|
||||
|
||||
|
||||
FunctionalTest = BaseFunctionalTest
|
@ -0,0 +1,10 @@
|
||||
from tests.functional.transport.pecan import base
|
||||
|
||||
|
||||
class ServiceControllerTest(base.FunctionalTest):
|
||||
|
||||
def test_get_all(self):
|
||||
pass
|
||||
#response = self.app.get('/health')
|
||||
|
||||
#self.assertEqual(204, response.status_code)
|
@ -0,0 +1,24 @@
|
||||
# Copyright (c) 2014 Rackspace, Inc.
|
||||
#
|
||||
# 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 tests.functional.transport.pecan import base
|
||||
|
||||
|
||||
class ServicesControllerTest(base.FunctionalTest):
|
||||
|
||||
def test_get_all(self):
|
||||
response = self.app.get('/v1.0/00001/services')
|
||||
|
||||
self.assertEqual(200, response.status_code)
|
@ -0,0 +1,28 @@
|
||||
# Copyright (c) 2014 Rackspace, Inc.
|
||||
#
|
||||
# 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 cdn.manager.default import v1
|
||||
|
||||
from tests.functional.transport.pecan import base
|
||||
|
||||
|
||||
class V1ControllerTest(base.FunctionalTest):
|
||||
|
||||
def test_get_all(self):
|
||||
response = self.app.get('/v1.0/00001')
|
||||
|
||||
self.assertEqual(200, response.status_code)
|
||||
# Temporary until actual implementation
|
||||
self.assertEqual(v1.JSON_HOME, response.json)
|
0
tests/functional/transport/pecan/hooks/__init__.py
Normal file
0
tests/functional/transport/pecan/hooks/__init__.py
Normal file
43
tests/functional/transport/pecan/hooks/test_context.py
Normal file
43
tests/functional/transport/pecan/hooks/test_context.py
Normal file
@ -0,0 +1,43 @@
|
||||
# Copyright (c) 2014 Rackspace, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import uuid
|
||||
|
||||
from cdn.manager.default import v1
|
||||
from tests.functional.transport.pecan import base
|
||||
|
||||
|
||||
class ContextHookTest(base.FunctionalTest):
|
||||
|
||||
def setUp(self):
|
||||
super(ContextHookTest, self).setUp()
|
||||
|
||||
self.headers = {'X-Auth-Token': str(uuid.uuid4())}
|
||||
|
||||
def test_project_id_in_header(self):
|
||||
self.headers['X-Project-Id'] = '000001'
|
||||
response = self.app.get('/v1.0', headers=self.headers)
|
||||
|
||||
self.assertEqual(200, response.status_code)
|
||||
|
||||
# Temporary until actual implementation
|
||||
self.assertEqual(v1.JSON_HOME, response.json)
|
||||
|
||||
def test_project_id_in_url(self):
|
||||
response = self.app.get('/v1.0/000001', headers=self.headers)
|
||||
|
||||
self.assertEqual(200, response.status_code)
|
||||
# Temporary until actual implementation
|
||||
self.assertEqual(v1.JSON_HOME, response.json)
|
0
tests/unit/transport/pecan/__init__.py
Normal file
0
tests/unit/transport/pecan/__init__.py
Normal file
77
tests/unit/transport/pecan/test_pecan_driver.py
Normal file
77
tests/unit/transport/pecan/test_pecan_driver.py
Normal file
@ -0,0 +1,77 @@
|
||||
# Copyright (c) 2014 Rackspace, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import unittest
|
||||
import threading
|
||||
import ctypes
|
||||
|
||||
import requests
|
||||
from oslo.config import cfg
|
||||
|
||||
from cdn.transport.pecan import driver
|
||||
|
||||
|
||||
def terminate_thread(thread):
|
||||
"""Terminates a python thread from another thread.
|
||||
|
||||
:param thread: a threading.Thread instance
|
||||
"""
|
||||
if not thread.isAlive():
|
||||
return
|
||||
|
||||
exc = ctypes.py_object(SystemExit)
|
||||
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(
|
||||
ctypes.c_long(thread.ident), exc)
|
||||
if res == 0:
|
||||
raise ValueError("nonexistent thread id")
|
||||
elif res > 1:
|
||||
# """if it returns a number greater than one, you're in trouble,
|
||||
# and you should call it again with exc=NULL to revert the effect"""
|
||||
ctypes.pythonapi.PyThreadState_SetAsyncExc(thread.ident, None)
|
||||
raise SystemError("PyThreadState_SetAsyncExc failed")
|
||||
|
||||
|
||||
class StoppableThread(threading.Thread):
|
||||
"""Thread class with a stop() method. The thread itself has to check
|
||||
regularly for the stopped() condition."""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(StoppableThread, self).__init__(**kwargs)
|
||||
self._stop = threading.Event()
|
||||
|
||||
def stop(self):
|
||||
self._stop.set()
|
||||
|
||||
def stopped(self):
|
||||
return self._stop.isSet()
|
||||
|
||||
|
||||
class TestPecanDriver(unittest.TestCase):
|
||||
def setUp(self):
|
||||
# Let manager = None for now
|
||||
self.pecan_driver = driver.PecanTransportDriver(cfg.CONF, None)
|
||||
|
||||
|
||||
def test_app_created(self):
|
||||
self.assertEquals(self.pecan_driver.app is not None, True)
|
||||
t = StoppableThread(target = self.pecan_driver.listen)
|
||||
t.start()
|
||||
#r = requests.get('http://127.0.0.1:8888')
|
||||
#print r
|
||||
#assertR
|
||||
t.stop()
|
||||
terminate_thread(t)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user