Add function tests for nimble API
This change add a functional test base for nimble and add some functional tests for instance_type APIs. Change-Id: I44fc4686891d75884860cab86e8c8e42186b5703
This commit is contained in:
parent
ffa8fbd39f
commit
e7e19fa522
@ -2,6 +2,6 @@
|
||||
test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
|
||||
OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
|
||||
OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \
|
||||
${PYTHON:-python} -m subunit.run discover -t ./ . $LISTOPT $IDOPTION
|
||||
${PYTHON:-python} -m subunit.run discover ${OS_TEST_PATH:-./nimble/tests} -t . $LISTOPT $IDOPTION
|
||||
test_id_option=--load-list $IDFILE
|
||||
test_list_option=--list
|
||||
|
0
nimble/tests/functional/__init__.py
Normal file
0
nimble/tests/functional/__init__.py
Normal file
@ -16,19 +16,14 @@
|
||||
# under the License.
|
||||
"""Base classes for API tests."""
|
||||
|
||||
# NOTE: Ported from ceilometer/tests/api.py (subsequently moved to
|
||||
# ceilometer/tests/api/__init__.py). This should be oslo'ified:
|
||||
# https://bugs.launchpad.net/ironic/+bug/1255115.
|
||||
|
||||
from oslo_config import cfg
|
||||
import pecan
|
||||
import pecan.testing
|
||||
from six.moves.urllib import parse as urlparse
|
||||
|
||||
from nimble import objects
|
||||
from nimble.tests.unit.db import base
|
||||
|
||||
PATH_PREFIX = '/v1'
|
||||
|
||||
cfg.CONF.import_group('keystone_authtoken', 'keystonemiddleware.auth_token')
|
||||
|
||||
|
||||
@ -40,7 +35,7 @@ class BaseApiTest(base.DbTestCase):
|
||||
framework.
|
||||
"""
|
||||
|
||||
SOURCE_DATA = {'test_source': {'somekey': '666'}}
|
||||
PATH_PREFIX = ''
|
||||
|
||||
def setUp(self):
|
||||
super(BaseApiTest, self).setUp()
|
||||
@ -48,6 +43,8 @@ class BaseApiTest(base.DbTestCase):
|
||||
group='keystone_authtoken')
|
||||
cfg.CONF.set_override("admin_user", "admin",
|
||||
group='keystone_authtoken')
|
||||
|
||||
objects.register_all()
|
||||
self.app = self._make_app()
|
||||
|
||||
def reset_pecan():
|
||||
@ -65,14 +62,13 @@ class BaseApiTest(base.DbTestCase):
|
||||
'modules': ['nimble.api'],
|
||||
'static_root': '%s/public' % root_dir,
|
||||
'template_path': '%s/api/templates' % root_dir,
|
||||
'acl_public_routes': ['/', '/v1'],
|
||||
'acl_public_routes': ['/', '/v1/.*'],
|
||||
},
|
||||
}
|
||||
return pecan.testing.load_test_app(self.app_config)
|
||||
|
||||
def _request_json(self, path, params, expect_errors=False, headers=None,
|
||||
method="post", extra_environ=None, status=None,
|
||||
path_prefix=PATH_PREFIX):
|
||||
method="post", extra_environ=None, status=None):
|
||||
"""Sends simulated HTTP request to Pecan test app.
|
||||
|
||||
:param path: url path of target service
|
||||
@ -87,17 +83,16 @@ class BaseApiTest(base.DbTestCase):
|
||||
:param status: expected status code of response
|
||||
:param path_prefix: prefix of the url path
|
||||
"""
|
||||
full_path = path_prefix + path
|
||||
print('%s: %s %s' % (method.upper(), full_path, params))
|
||||
response = getattr(self.app, "%s_json" % method)(
|
||||
str(full_path),
|
||||
str(path),
|
||||
params=params,
|
||||
headers=headers,
|
||||
status=status,
|
||||
extra_environ=extra_environ,
|
||||
expect_errors=expect_errors
|
||||
)
|
||||
print('GOT:%s' % response)
|
||||
if not expect_errors:
|
||||
response = response.json
|
||||
return response
|
||||
|
||||
def put_json(self, path, params, expect_errors=False, headers=None,
|
||||
@ -113,7 +108,8 @@ class BaseApiTest(base.DbTestCase):
|
||||
with the request
|
||||
:param status: expected status code of response
|
||||
"""
|
||||
return self._request_json(path=path, params=params,
|
||||
full_path = self.PATH_PREFIX + path
|
||||
return self._request_json(path=full_path, params=params,
|
||||
expect_errors=expect_errors,
|
||||
headers=headers, extra_environ=extra_environ,
|
||||
status=status, method="put")
|
||||
@ -131,7 +127,8 @@ class BaseApiTest(base.DbTestCase):
|
||||
with the request
|
||||
:param status: expected status code of response
|
||||
"""
|
||||
return self._request_json(path=path, params=params,
|
||||
full_path = self.PATH_PREFIX + path
|
||||
return self._request_json(path=full_path, params=params,
|
||||
expect_errors=expect_errors,
|
||||
headers=headers, extra_environ=extra_environ,
|
||||
status=status, method="post")
|
||||
@ -149,13 +146,14 @@ class BaseApiTest(base.DbTestCase):
|
||||
with the request
|
||||
:param status: expected status code of response
|
||||
"""
|
||||
return self._request_json(path=path, params=params,
|
||||
full_path = self.PATH_PREFIX + path
|
||||
return self._request_json(path=full_path, params=params,
|
||||
expect_errors=expect_errors,
|
||||
headers=headers, extra_environ=extra_environ,
|
||||
status=status, method="patch")
|
||||
|
||||
def delete(self, path, expect_errors=False, headers=None,
|
||||
extra_environ=None, status=None, path_prefix=PATH_PREFIX):
|
||||
extra_environ=None, status=None):
|
||||
"""Sends simulated HTTP DELETE request to Pecan test app.
|
||||
|
||||
:param path: url path of target service
|
||||
@ -167,18 +165,16 @@ class BaseApiTest(base.DbTestCase):
|
||||
:param status: expected status code of response
|
||||
:param path_prefix: prefix of the url path
|
||||
"""
|
||||
full_path = path_prefix + path
|
||||
print('DELETE: %s' % (full_path))
|
||||
full_path = self.PATH_PREFIX + path
|
||||
response = self.app.delete(str(full_path),
|
||||
headers=headers,
|
||||
status=status,
|
||||
extra_environ=extra_environ,
|
||||
expect_errors=expect_errors)
|
||||
print('GOT:%s' % response)
|
||||
return response
|
||||
|
||||
def get_json(self, path, expect_errors=False, headers=None,
|
||||
extra_environ=None, q=[], path_prefix=PATH_PREFIX, **params):
|
||||
extra_environ=None, q=[], **params):
|
||||
"""Sends simulated HTTP GET request to Pecan test app.
|
||||
|
||||
:param path: url path of target service
|
||||
@ -192,7 +188,7 @@ class BaseApiTest(base.DbTestCase):
|
||||
:param path_prefix: prefix of the url path
|
||||
:param params: content for wsgi.input of request
|
||||
"""
|
||||
full_path = path_prefix + path
|
||||
full_path = self.PATH_PREFIX + path
|
||||
query_params = {'q.field': [],
|
||||
'q.value': [],
|
||||
'q.op': [],
|
||||
@ -204,7 +200,6 @@ class BaseApiTest(base.DbTestCase):
|
||||
all_params.update(params)
|
||||
if q:
|
||||
all_params.update(query_params)
|
||||
print('GET: %s %r' % (full_path, all_params))
|
||||
response = self.app.get(full_path,
|
||||
params=all_params,
|
||||
headers=headers,
|
||||
@ -212,22 +207,4 @@ class BaseApiTest(base.DbTestCase):
|
||||
expect_errors=expect_errors)
|
||||
if not expect_errors:
|
||||
response = response.json
|
||||
print('GOT:%s' % response)
|
||||
return response
|
||||
|
||||
def validate_link(self, link, bookmark=False):
|
||||
"""Checks if the given link can get correct data."""
|
||||
# removes the scheme and net location parts of the link
|
||||
url_parts = list(urlparse.urlparse(link))
|
||||
url_parts[0] = url_parts[1] = ''
|
||||
|
||||
# bookmark link should not have the version in the URL
|
||||
if bookmark and url_parts[2].startswith(PATH_PREFIX):
|
||||
return False
|
||||
|
||||
full_path = urlparse.urlunparse(url_parts)
|
||||
try:
|
||||
self.get_json(full_path, path_prefix='')
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
@ -13,13 +13,13 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from nimble.tests.unit.api import base
|
||||
from nimble.tests.functional import api
|
||||
|
||||
|
||||
class TestRoot(base.BaseApiTest):
|
||||
class TestRoot(api.BaseApiTest):
|
||||
|
||||
def test_get_root(self):
|
||||
response = self.get_json('/', path_prefix='')
|
||||
response = self.get_json('/')
|
||||
# Check fields are not empty
|
||||
[self.assertNotIn(f, ['', []]) for f in response]
|
||||
|
20
nimble/tests/functional/api/v1/__init__.py
Normal file
20
nimble/tests/functional/api/v1/__init__.py
Normal file
@ -0,0 +1,20 @@
|
||||
#
|
||||
# Copyright 2016 Huawei Technologies Co., Ltd.
|
||||
#
|
||||
# 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 nimble.tests.functional import api
|
||||
|
||||
|
||||
class APITestV1(api.BaseApiTest):
|
||||
PATH_PREFIX = '/v1'
|
66
nimble/tests/functional/api/v1/test_instance_types.py
Normal file
66
nimble/tests/functional/api/v1/test_instance_types.py
Normal file
@ -0,0 +1,66 @@
|
||||
#
|
||||
# Copyright 2016 Huawei Technologies Co., Ltd.
|
||||
#
|
||||
# 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 mock
|
||||
|
||||
from nimble.tests.functional.api import v1 as v1_test
|
||||
|
||||
|
||||
class TestInstanceType(v1_test.APITestV1):
|
||||
|
||||
TYPE_UUIDS = ['ff28b5a2-73e5-431c-b4b7-1b96b74bca7b',
|
||||
'94baf80e-2bae-4c3e-8dab-38b5441e7097',
|
||||
'4bcfff85-c55a-493b-b544-b6c90b8fb397',
|
||||
'e50fb289-4ee1-47dd-b371-6ca39af12888']
|
||||
|
||||
def setUp(self):
|
||||
super(TestInstanceType, self).setUp()
|
||||
|
||||
@mock.patch('oslo_utils.uuidutils.generate_uuid')
|
||||
def _prepare_instance_types(self, mocked):
|
||||
mocked.side_effect = self.TYPE_UUIDS
|
||||
for i in xrange(4):
|
||||
body = {"name": "test" + str(i),
|
||||
"description": "just test" + str(i)}
|
||||
self.post_json('/types', body, status=201)
|
||||
|
||||
def test_instance_type_post(self):
|
||||
body = {"name": "test", "description": "just test"}
|
||||
resp = self.post_json('/types', body, status=201)
|
||||
self.assertEqual('test', resp['name'])
|
||||
self.assertEqual('just test', resp['description'])
|
||||
self.assertEqual(True, resp['is_public'])
|
||||
self.assertIn('uuid', resp)
|
||||
self.assertIn('extra_specs', resp)
|
||||
self.assertIn('links', resp)
|
||||
|
||||
def test_instance_type_get_all(self):
|
||||
self._prepare_instance_types()
|
||||
resp = self.get_json('/types')
|
||||
self.assertEqual(4, len(resp['types']))
|
||||
|
||||
def test_instance_type_get_one(self):
|
||||
self._prepare_instance_types()
|
||||
resp = self.get_json('/types/' + self.TYPE_UUIDS[0])
|
||||
self.assertEqual('test0', resp['name'])
|
||||
self.assertEqual('just test0', resp['description'])
|
||||
|
||||
def test_instance_type_delete(self):
|
||||
self._prepare_instance_types()
|
||||
resp = self.get_json('/types')
|
||||
self.assertEqual(4, len(resp['types']))
|
||||
self.delete('/types/' + self.TYPE_UUIDS[0], status=204)
|
||||
resp = self.get_json('/types')
|
||||
self.assertEqual(3, len(resp['types']))
|
@ -20,7 +20,7 @@ from oslo_config import cfg
|
||||
|
||||
from nimble.api import hooks
|
||||
from nimble.common import context
|
||||
from nimble.tests.unit.api import base
|
||||
from nimble.tests import base
|
||||
|
||||
|
||||
class FakeRequest(object):
|
||||
@ -91,7 +91,7 @@ def fake_headers(admin=False):
|
||||
return headers
|
||||
|
||||
|
||||
class TestContextHook(base.BaseApiTest):
|
||||
class TestContextHook(base.BaseTestCase):
|
||||
@mock.patch.object(context, 'RequestContext')
|
||||
def test_context_hook(self, mock_ctx):
|
||||
headers = fake_headers(admin=True)
|
||||
@ -142,13 +142,16 @@ class TestContextHook(base.BaseApiTest):
|
||||
reqstate.response.headers['Openstack-Request-Id'])
|
||||
|
||||
def test_context_hook_after_miss_context(self):
|
||||
response = self.get_json('/bad/path',
|
||||
expect_errors=True)
|
||||
headers = fake_headers(admin=True)
|
||||
reqstate = FakeRequestState(headers=headers)
|
||||
reqstate.request.context = {}
|
||||
context_hook = hooks.ContextHook(None)
|
||||
context_hook.after(reqstate)
|
||||
self.assertNotIn('Openstack-Request-Id',
|
||||
response.headers)
|
||||
reqstate.response.headers)
|
||||
|
||||
|
||||
class TestPublicUrlHook(base.BaseApiTest):
|
||||
class TestPublicUrlHook(base.BaseTestCase):
|
||||
|
||||
def test_before_host_url(self):
|
||||
headers = fake_headers()
|
||||
|
6
tox.ini
6
tox.ini
@ -1,6 +1,6 @@
|
||||
[tox]
|
||||
minversion = 2.0
|
||||
envlist = py35-constraints,py34-constraints,py27-constraints,pypy-constraints,pep8-constraints
|
||||
envlist = py35-constraints,py34-constraints,py27-constraints,pypy-constraints,pep8-constraints,functional
|
||||
skipsdist = True
|
||||
|
||||
[testenv]
|
||||
@ -51,6 +51,10 @@ commands = python setup.py build_sphinx
|
||||
[testenv:debug]
|
||||
commands = oslo_debug_helper {posargs}
|
||||
|
||||
[testenv:functional]
|
||||
setenv = OS_TEST_PATH=nimble/tests/functional/
|
||||
commands = python setup.py testr --slowest --testr-args="{posargs}"
|
||||
|
||||
[testenv:debug-constraints]
|
||||
install_command = {[testenv:common-constraints]install_command}
|
||||
commands = oslo_debug_helper {posargs}
|
||||
|
Loading…
Reference in New Issue
Block a user