Move integrated tests to 'functional' directory

Functional unit tests should not be a part of unit
tests job. This patch adds new tox environment to run
functional tests:
    $ tox -e functional

It also removes logging from functional tests. Some of log calls were
replaced with asserts.

Related Implements: blueprint cinder-integrated-tests

Change-Id: I0ebfef2fe05f502cd5fb08fbc8af09008949e457
This commit is contained in:
Ivan Kolodyazhny 2016-01-14 22:20:56 +02:00
parent a5d565b1f1
commit 6bdc836965
13 changed files with 47 additions and 117 deletions

View File

@ -2,7 +2,7 @@
test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \ test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \ OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \ OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \
${PYTHON:-python} -m subunit.run discover -t ./ ./cinder/tests $LISTOPT $IDOPTION ${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./cinder/tests/unit} $LISTOPT $IDOPTION
test_id_option=--load-list $IDFILE test_id_option=--load-list $IDFILE
test_list_option=--list test_list_option=--list

View File

@ -12,16 +12,12 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from oslo_log import log as logging
from oslo_serialization import jsonutils from oslo_serialization import jsonutils
from oslo_utils import netutils from oslo_utils import netutils
import requests import requests
from six.moves import urllib from six.moves import urllib
from cinder.i18n import _, _LI from cinder.i18n import _
LOG = logging.getLogger(__name__)
class OpenStackApiException(Exception): class OpenStackApiException(Exception):
@ -94,10 +90,6 @@ class TestOpenStackClient(object):
relative_url = parsed_url.path relative_url = parsed_url.path
if parsed_url.query: if parsed_url.query:
relative_url = relative_url + "?" + parsed_url.query relative_url = relative_url + "?" + parsed_url.query
LOG.info(_LI("Doing %(method)s on %(relative_url)s"),
{'method': method, 'relative_url': relative_url})
if body:
LOG.info(_LI("Body: %s") % body)
if port: if port:
_url = "%s://%s:%d%s" % (scheme, hostname, int(port), relative_url) _url = "%s://%s:%d%s" % (scheme, hostname, int(port), relative_url)
@ -121,8 +113,6 @@ class TestOpenStackClient(object):
headers=headers) headers=headers)
http_status = response.status_code http_status = response.status_code
LOG.debug("%(auth_uri)s => code %(http_status)s",
{'auth_uri': auth_uri, 'http_status': http_status})
if http_status == 401: if http_status == 401:
raise OpenStackApiAuthenticationException(response=response) raise OpenStackApiAuthenticationException(response=response)
@ -144,8 +134,6 @@ class TestOpenStackClient(object):
response = self.request(full_uri, **kwargs) response = self.request(full_uri, **kwargs)
http_status = response.status_code http_status = response.status_code
LOG.debug("%(relative_uri)s => code %(http_status)s",
{'relative_uri': relative_uri, 'http_status': http_status})
if check_response_status: if check_response_status:
if http_status not in check_response_status: if http_status not in check_response_status:
@ -162,7 +150,6 @@ class TestOpenStackClient(object):
def _decode_json(self, response): def _decode_json(self, response):
body = response.text body = response.text
LOG.debug("Decoding JSON: %s" % (body))
if body: if body:
return jsonutils.loads(body) return jsonutils.loads(body)
else: else:

View File

@ -14,7 +14,7 @@
# under the License. # under the License.
""" """
Provides common functionality for integrated unit tests Provides common functionality for functional tests
""" """
import os.path import os.path
import random import random
@ -24,15 +24,13 @@ import uuid
import fixtures import fixtures
import mock import mock
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log as logging
from cinder import service from cinder import service
from cinder import test # For the flags from cinder import test # For the flags
from cinder.tests.unit.integrated.api import client from cinder.tests.functional.api import client
CONF = cfg.CONF CONF = cfg.CONF
LOG = logging.getLogger(__name__)
def generate_random_alphanumeric(length): def generate_random_alphanumeric(length):
@ -56,12 +54,11 @@ def generate_new_element(items, prefix, numeric=False):
candidate = prefix + generate_random_alphanumeric(8) candidate = prefix + generate_random_alphanumeric(8)
if candidate not in items: if candidate not in items:
return candidate return candidate
LOG.debug("Random collision on %s", candidate)
class _IntegratedTestBase(test.TestCase): class _FunctionalTestBase(test.TestCase):
def setUp(self): def setUp(self):
super(_IntegratedTestBase, self).setUp() super(_FunctionalTestBase, self).setUp()
f = self._get_flags() f = self._get_flags()
self.flags(**f) self.flags(**f)
@ -83,7 +80,7 @@ class _IntegratedTestBase(test.TestCase):
def _start_api_service(self): def _start_api_service(self):
default_conf = os.path.abspath(os.path.join( default_conf = os.path.abspath(os.path.join(
os.path.dirname(__file__), '..', '..', '..', '..', os.path.dirname(__file__), '..', '..', '..',
'etc/cinder/api-paste.ini')) 'etc/cinder/api-paste.ini'))
CONF.api_paste_config = default_conf CONF.api_paste_config = default_conf
self.osapi = service.WSGIService("osapi_volume") self.osapi = service.WSGIService("osapi_volume")
@ -91,7 +88,6 @@ class _IntegratedTestBase(test.TestCase):
# FIXME(ja): this is not the auth url - this is the service url # FIXME(ja): this is not the auth url - this is the service url
# FIXME(ja): this needs fixed in nova as well # FIXME(ja): this needs fixed in nova as well
self.auth_url = 'http://%s:%s/v2' % (self.osapi.host, self.osapi.port) self.auth_url = 'http://%s:%s/v2' % (self.osapi.host, self.osapi.port)
LOG.warning(self.auth_url)
def _get_flags(self): def _get_flags(self):
"""An opportunity to setup flags, before the services are started.""" """An opportunity to setup flags, before the services are started."""
@ -122,7 +118,6 @@ class _IntegratedTestBase(test.TestCase):
server = {} server = {}
image = self.api.get_images()[0] image = self.api.get_images()[0]
LOG.debug("Image: %s", image)
if 'imageRef' in image: if 'imageRef' in image:
image_href = image['imageRef'] image_href = image['imageRef']
@ -135,7 +130,6 @@ class _IntegratedTestBase(test.TestCase):
# Set a valid flavorId # Set a valid flavorId
flavor = self.api.get_flavors()[0] flavor = self.api.get_flavors()[0]
LOG.debug("Using flavor: %s", flavor)
server['flavorRef'] = 'http://fake.server/%s' % flavor['id'] server['flavorRef'] = 'http://fake.server/%s' % flavor['id']
# Set a valid server name # Set a valid server name

View File

@ -1,5 +1,4 @@
# Copyright (c) 2011 X.commerce, a business unit of eBay Inc. # Copyright 2011 Justin Santa Barbara
# Copyright 2011 OpenStack Foundation
# 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
@ -14,6 +13,7 @@
# 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 iso8601 import iso8601
from lxml import etree from lxml import etree
from oslo_config import cfg from oslo_config import cfg
@ -23,23 +23,28 @@ import webob
from cinder.api import extensions from cinder.api import extensions
from cinder.api.v1 import router from cinder.api.v1 import router
from cinder.api import xmlutil from cinder.api import xmlutil
from cinder import test from cinder.tests.functional import functional_helpers
NS = "{http://docs.openstack.org/common/api/v1.0}" NS = "{http://docs.openstack.org/common/api/v1.0}"
CONF = cfg.CONF CONF = cfg.CONF
class ExtensionTestCase(test.TestCase): class ExtensionTestCase(functional_helpers._FunctionalTestBase):
def setUp(self): def _get_flags(self):
super(ExtensionTestCase, self).setUp() f = super(ExtensionTestCase, self)._get_flags()
ext_list = CONF.osapi_volume_extension[:] f['osapi_volume_extension'] = CONF.osapi_volume_extension[:]
fox = ('cinder.tests.unit.api.extensions.foxinsocks.Foxinsocks') f['osapi_volume_extension'].append(
if fox not in ext_list: 'cinder.tests.functional.api.foxinsocks.Foxinsocks')
ext_list.append(fox) return f
self.flags(osapi_volume_extension=ext_list)
class ExtensionsTest(ExtensionTestCase):
def test_get_foxnsocks(self):
"""Simple check that fox-n-socks works."""
response = self.api.api_request('/foxnsocks')
foxnsocks = response.text
self.assertEqual('Try to say this Mr. Knox, sir...', foxnsocks)
class ExtensionControllerTest(ExtensionTestCase): class ExtensionControllerTest(ExtensionTestCase):
@ -183,7 +188,7 @@ class StubExtensionManager(object):
return controller_extensions return controller_extensions
class ExtensionControllerIdFormatTest(test.TestCase): class ExtensionControllerIdFormatTest(ExtensionTestCase):
def _bounce_id(self, test_id): def _bounce_id(self, test_id):

View File

@ -13,17 +13,11 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from oslo_log import log as logging from cinder.tests.functional import functional_helpers
from cinder.tests.unit.integrated import integrated_helpers
LOG = logging.getLogger(__name__) class LoginTest(functional_helpers._FunctionalTestBase):
class LoginTest(integrated_helpers._IntegratedTestBase):
def test_login(self): def test_login(self):
"""Simple check - we list volumes - so we know we're logged in.""" """Simple check - we list volumes - so we know we're logged in."""
volumes = self.api.get_volumes() volumes = self.api.get_volumes()
for volume in volumes: self.assertIsNotNone(volumes)
LOG.debug("volume: %s" % volume)

View File

@ -15,22 +15,24 @@
import time import time
from oslo_log import log as logging
import testtools import testtools
from cinder import service
from cinder.tests.functional.api import client
from cinder.tests.functional import functional_helpers
from cinder.tests.unit import fake_driver from cinder.tests.unit import fake_driver
from cinder.tests.unit.integrated.api import client
from cinder.tests.unit.integrated import integrated_helpers
LOG = logging.getLogger(__name__) class VolumesTest(functional_helpers._FunctionalTestBase):
class VolumesTest(integrated_helpers._IntegratedTestBase):
def setUp(self): def setUp(self):
super(VolumesTest, self).setUp() super(VolumesTest, self).setUp()
fake_driver.LoggingVolumeDriver.clear_logs() fake_driver.LoggingVolumeDriver.clear_logs()
def _start_api_service(self):
self.osapi = service.WSGIService("osapi_volume")
self.osapi.start()
self.auth_url = 'http://%s:%s/v2' % (self.osapi.host, self.osapi.port)
def _get_flags(self): def _get_flags(self):
f = super(VolumesTest, self)._get_flags() f = super(VolumesTest, self)._get_flags()
f['volume_driver'] = \ f['volume_driver'] = \
@ -40,14 +42,12 @@ class VolumesTest(integrated_helpers._IntegratedTestBase):
def test_get_volumes_summary(self): def test_get_volumes_summary(self):
"""Simple check that listing volumes works.""" """Simple check that listing volumes works."""
volumes = self.api.get_volumes(False) volumes = self.api.get_volumes(False)
for volume in volumes: self.assertIsNotNone(volumes)
LOG.debug("volume: %s", volume)
def test_get_volumes(self): def test_get_volumes(self):
"""Simple check that listing volumes works.""" """Simple check that listing volumes works."""
volumes = self.api.get_volumes() volumes = self.api.get_volumes()
for volume in volumes: self.assertIsNotNone(volumes)
LOG.debug("volume: %s", volume)
def _poll_while(self, volume_id, continue_states, max_retries=5): def _poll_while(self, volume_id, continue_states, max_retries=5):
"""Poll (briefly) while the state is in continue_states.""" """Poll (briefly) while the state is in continue_states."""
@ -57,11 +57,8 @@ class VolumesTest(integrated_helpers._IntegratedTestBase):
found_volume = self.api.get_volume(volume_id) found_volume = self.api.get_volume(volume_id)
except client.OpenStackApiNotFoundException: except client.OpenStackApiNotFoundException:
found_volume = None found_volume = None
LOG.debug("Got 404, proceeding")
break break
LOG.debug("Found %s", found_volume)
self.assertEqual(volume_id, found_volume['id']) self.assertEqual(volume_id, found_volume['id'])
if found_volume['status'] not in continue_states: if found_volume['status'] not in continue_states:
@ -79,7 +76,6 @@ class VolumesTest(integrated_helpers._IntegratedTestBase):
# Create volume # Create volume
created_volume = self.api.post_volume({'volume': {'size': 1}}) created_volume = self.api.post_volume({'volume': {'size': 1}})
LOG.debug("created_volume: %s", created_volume)
self.assertTrue(created_volume['id']) self.assertTrue(created_volume['id'])
created_volume_id = created_volume['id'] created_volume_id = created_volume['id']
@ -107,12 +103,9 @@ class VolumesTest(integrated_helpers._IntegratedTestBase):
# Should be gone # Should be gone
self.assertFalse(found_volume) self.assertFalse(found_volume)
LOG.debug("Logs: %s", fake_driver.LoggingVolumeDriver.all_logs())
create_actions = fake_driver.LoggingVolumeDriver.logs_like( create_actions = fake_driver.LoggingVolumeDriver.logs_like(
'create_volume', 'create_volume',
id=created_volume_id) id=created_volume_id)
LOG.debug("Create_Actions: %s", create_actions)
self.assertEqual(1, len(create_actions)) self.assertEqual(1, len(create_actions))
create_action = create_actions[0] create_action = create_actions[0]
@ -144,7 +137,6 @@ class VolumesTest(integrated_helpers._IntegratedTestBase):
created_volume = self.api.post_volume( created_volume = self.api.post_volume(
{'volume': {'size': 1, {'volume': {'size': 1,
'metadata': metadata}}) 'metadata': metadata}})
LOG.debug("created_volume: %s", created_volume)
self.assertTrue(created_volume['id']) self.assertTrue(created_volume['id'])
created_volume_id = created_volume['id'] created_volume_id = created_volume['id']
@ -161,7 +153,6 @@ class VolumesTest(integrated_helpers._IntegratedTestBase):
created_volume = self.api.post_volume( created_volume = self.api.post_volume(
{'volume': {'size': 1, {'volume': {'size': 1,
'availability_zone': availability_zone}}) 'availability_zone': availability_zone}})
LOG.debug("created_volume: %s", created_volume)
self.assertTrue(created_volume['id']) self.assertTrue(created_volume['id'])
created_volume_id = created_volume['id'] created_volume_id = created_volume['id']

View File

@ -14,16 +14,12 @@
# under the License. # under the License.
from lxml import etree from lxml import etree
from oslo_log import log as logging
from cinder.api import common from cinder.api import common
from cinder.tests.unit.integrated import integrated_helpers from cinder.tests.functional import functional_helpers
LOG = logging.getLogger(__name__) class XmlTests(functional_helpers._FunctionalTestBase):
class XmlTests(integrated_helpers._IntegratedTestBase):
"""Some basic XML sanity checks.""" """Some basic XML sanity checks."""
# FIXME(ja): does cinder need limits? # FIXME(ja): does cinder need limits?
@ -44,6 +40,5 @@ class XmlTests(integrated_helpers._IntegratedTestBase):
response = self.api.api_request('/volumes', headers=headers, response = self.api.api_request('/volumes', headers=headers,
stream=True) stream=True)
data = response.raw data = response.raw
LOG.warning("data: %s", data)
root = etree.parse(data).getroot() root = etree.parse(data).getroot()
self.assertEqual(common.XML_NS_V2, root.nsmap.get(None)) self.assertEqual(common.XML_NS_V2, root.nsmap.get(None))

View File

@ -1,40 +0,0 @@
# Copyright 2011 Justin Santa Barbara
# 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 oslo_config import cfg
from oslo_log import log as logging
from cinder.tests.unit.integrated import integrated_helpers
CONF = cfg.CONF
LOG = logging.getLogger(__name__)
class ExtensionsTest(integrated_helpers._IntegratedTestBase):
def _get_flags(self):
f = super(ExtensionsTest, self)._get_flags()
f['osapi_volume_extension'] = CONF.osapi_volume_extension[:]
f['osapi_volume_extension'].append(
'cinder.tests.unit.api.extensions.foxinsocks.Foxinsocks')
return f
def test_get_foxnsocks(self):
"""Simple check that fox-n-socks works."""
response = self.api.api_request('/foxnsocks')
foxnsocks = response.text
self.assertEqual('Try to say this Mr. Knox, sir...', foxnsocks)

View File

@ -22,7 +22,7 @@ deps = -r{toxinidir}/test-requirements.txt
# to ncpu, to specify something else use # to ncpu, to specify something else use
# the concurrency=<n> option. # the concurrency=<n> option.
# call ie: 'tox -epy27 -- --concurrency=4' # call ie: 'tox -epy27 -- --concurrency=4'
commands = ostestr {posargs} commands = python setup.py testr --testr-args='{posargs}'
whitelist_externals = bash whitelist_externals = bash
passenv = *_proxy *_PROXY passenv = *_proxy *_PROXY
@ -37,6 +37,10 @@ install_command = pip install -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstac
commands = commands =
ostestr --whitelist_file=tests-py3.txt ostestr --whitelist_file=tests-py3.txt
[testenv:functional]
setenv =
OS_TEST_PATH = ./cinder/tests/functional
[testenv:py34-constraints] [testenv:py34-constraints]
install_command = {[testenv:common-constraints]install_command} install_command = {[testenv:common-constraints]install_command}
commands = {[testenv:py34]commands} commands = {[testenv:py34]commands}