Add first tempest test

- First functional test for the API endpoint /info
- Move all unit tests to almanach.tests.unit like
other OpenStack projects

Change-Id: I8017aec28a060024f63bee59173b3c1df8879edb
This commit is contained in:
Frédéric Guillot 2016-11-25 16:37:53 -05:00
parent d77d2a90b6
commit 1ea561c3c8
51 changed files with 313 additions and 45 deletions

2
.gitignore vendored
View File

@ -1,10 +1,12 @@
.idea .idea
.tox .tox
*.iml *.iml
*.log
*.pyc *.pyc
*.coverage *.coverage
*.egg* *.egg*
.DS_Store .DS_Store
.testrepository
AUTHORS AUTHORS
ChangeLog ChangeLog
doc/build doc/build

8
.testr.conf Normal file
View File

@ -0,0 +1,8 @@
[DEFAULT]
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 . ./almanach/tests/tempest/tests $LISTOPT $IDOPTION
test_id_option=--load-list $IDFILE
test_list_option=--list

View File

@ -0,0 +1,45 @@
===============================================
Tempest Integration of Almanach
===============================================
This directory contains Tempest tests to cover the Almanach project.
Tempest Configuration File
--------------------------
Example of config file for devstack:
.. code:: bash
[DEFAULT]
[identity]
auth_version = v3
uri = http://192.168.50.50:5000/v2.0
uri_v3 = http://192.168.50.50:5000/v3
[auth]
admin_username = admin
admin_password = secret
admin_project_name = admin
admin_domain_name = Default
use_dynamic_credentials = true
Here, :code:`192.168.50.50` is your devstack IP address.
Run tests on your local machine
-------------------------------
1. Create a virtualenv from :code:`https://git.openstack.org/openstack/tempest.git
2. Create a custom :code:`tempest.conf`, by default :code:`/etc/tempest/tempest.conf` is loaded
3. List the tests: :code:`testr list-tests`
4. Run the tests with testr or tempest:
- :code:`testr run`
- :code:`tempest run`
Run tests in devstack
---------------------
- :code:`cd /opt/stack/almanach`
- :code:`tempest run`

View File

@ -0,0 +1,24 @@
# Copyright 2016 Internap.
#
# 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 tempest import clients
from almanach.tests.tempest.services import almanach_client
class Manager(clients.Manager):
def __init__(self, credentials=None, service=None):
super(Manager, self).__init__(credentials, service)
self.almanach_client = almanach_client.AlmanachClient(self.auth_provider)

View File

@ -0,0 +1,44 @@
# Copyright 2016 Internap.
#
# 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
service_available_group = cfg.OptGroup(name="service_available",
title="Available OpenStack Services")
ServiceAvailableGroup = [
cfg.BoolOpt("almanach",
default=True,
help="Whether or not Almanach is expected to be available"),
]
usage_group = cfg.OptGroup(name="almanach",
title="Usage Service Options")
UsageGroup = [
cfg.StrOpt("region",
default="",
help="The usage region name to use. If empty, the value "
"of identity.region is used instead. If no such region "
"is found in the service catalog, the first found one is "
"used."),
cfg.StrOpt("catalog_type",
default="usage",
help="Catalog type for Almanach."),
cfg.StrOpt('endpoint_type',
default='publicURL',
choices=['public', 'admin', 'internal',
'publicURL', 'adminURL', 'internalURL'],
help="The endpoint type to use for the usage service.")
]

View File

@ -0,0 +1,41 @@
# Copyright 2016 Internap.
#
# 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 tempest import config
from tempest.test_discover import plugins
from almanach.tests.tempest import config as project_config
class AlmanachTempestPlugin(plugins.TempestPlugin):
def load_tests(self):
base_path = os.path.split(os.path.dirname(
os.path.abspath(__file__)))[0]
test_dir = "tempest/tests"
full_test_dir = os.path.join(base_path, test_dir)
return full_test_dir, base_path
def register_opts(self, conf):
config.register_opt_group(
conf, project_config.service_available_group,
project_config.ServiceAvailableGroup)
config.register_opt_group(conf, project_config.usage_group,
project_config.UsageGroup)
def get_opt_lists(self):
return [(project_config.usage_group.name,
project_config.UsageGroup)]

View File

@ -0,0 +1,3 @@
from almanach.tests.tempest.services.almanach_client import AlmanachClient
__all__ = ['AlmanachClient']

View File

@ -0,0 +1,32 @@
# Copyright 2016 Internap.
#
# 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 tempest import config
from tempest.lib.common import rest_client
CONF = config.CONF
class AlmanachClient(rest_client.RestClient):
def __init__(self, auth_provider):
super(AlmanachClient, self).__init__(
auth_provider,
CONF.almanach.catalog_type,
CONF.almanach.region or CONF.identity.region,
endpoint_type=CONF.almanach.endpoint_type)
def get_version(self):
resp, response_body = self.get('info')
return resp, response_body

View File

@ -0,0 +1,40 @@
# Copyright 2016 Internap.
#
# 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 tempest import config
import tempest.test
from almanach.tests.tempest import clients
CONF = config.CONF
class BaseAlmanachTest(tempest.test.BaseTestCase):
@classmethod
def skip_checks(cls):
super(BaseAlmanachTest, cls).skip_checks()
@classmethod
def setup_credentials(cls):
cls.set_network_resources()
super(BaseAlmanachTest, cls).setup_credentials()
@classmethod
def setup_clients(cls):
super(BaseAlmanachTest, cls).setup_clients()
cred_provider = cls._get_credentials_provider()
credentials = cred_provider.get_creds_by_roles(['admin']).credentials
cls.os = clients.Manager(credentials=credentials)
cls.almanach_client = cls.os.almanach_client

View File

@ -0,0 +1,31 @@
# Copyright 2016 Internap.
#
# 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_serialization import jsonutils as json
from almanach.tests.tempest.tests.api import base
class TestVersion(base.BaseAlmanachTest):
@classmethod
def resource_setup(cls):
super(TestVersion, cls).resource_setup()
def test_get_version(self):
resp, response_body = self.almanach_client.get_version()
self.assertEqual(resp.status, 200)
response_body = json.loads(response_body)
self.assertIsInstance(response_body, dict)

View File

@ -20,8 +20,7 @@ from hamcrest import raises
from almanach.api.auth import keystone_auth from almanach.api.auth import keystone_auth
from almanach.core import exception from almanach.core import exception
from almanach.tests.unit import base
from tests import base
class KeystoneAuthenticationTest(base.BaseTestCase): class KeystoneAuthenticationTest(base.BaseTestCase):

View File

@ -20,8 +20,7 @@ from hamcrest import raises
from almanach.api.auth import mixed_auth from almanach.api.auth import mixed_auth
from almanach.core import exception from almanach.core import exception
from almanach.tests.unit import base
from tests import base
class MixedAuthenticationTest(base.BaseTestCase): class MixedAuthenticationTest(base.BaseTestCase):

View File

@ -19,8 +19,7 @@ from hamcrest import raises
from almanach.api.auth import private_key_auth from almanach.api.auth import private_key_auth
from almanach.core import exception from almanach.core import exception
from almanach.tests.unit import base
from tests import base
class PrivateKeyAuthenticationTest(base.BaseTestCase): class PrivateKeyAuthenticationTest(base.BaseTestCase):

View File

@ -20,7 +20,7 @@ import oslo_serialization
from almanach.api.v1 import routes from almanach.api.v1 import routes
from almanach.core import exception from almanach.core import exception
from tests import base from almanach.tests.unit import base
class BaseApi(base.BaseTestCase): class BaseApi(base.BaseTestCase):

View File

@ -15,7 +15,7 @@
from hamcrest import assert_that from hamcrest import assert_that
from hamcrest import equal_to from hamcrest import equal_to
from tests.api.base_api import BaseApi from almanach.tests.unit.api.base_api import BaseApi
class ApiAuthenticationTest(BaseApi): class ApiAuthenticationTest(BaseApi):

View File

@ -20,9 +20,9 @@ from hamcrest import is_
from voluptuous import Invalid from voluptuous import Invalid
from almanach.core import exception from almanach.core import exception
from tests.api.base_api import BaseApi from almanach.tests.unit.api.base_api import BaseApi
from tests.builder import a from almanach.tests.unit.builder import a
from tests.builder import instance from almanach.tests.unit.builder import instance
class ApiEntityTest(BaseApi): class ApiEntityTest(BaseApi):

View File

@ -16,7 +16,7 @@ from hamcrest import assert_that
from hamcrest import equal_to from hamcrest import equal_to
from hamcrest import has_key from hamcrest import has_key
from tests.api.base_api import BaseApi from almanach.tests.unit.api.base_api import BaseApi
class ApiInfoTest(BaseApi): class ApiInfoTest(BaseApi):

View File

@ -20,10 +20,10 @@ from hamcrest import has_length
from hamcrest import is_ from hamcrest import is_
from almanach.core import exception from almanach.core import exception
from tests.api.base_api import a_date_matching from almanach.tests.unit.api.base_api import a_date_matching
from tests.api.base_api import BaseApi from almanach.tests.unit.api.base_api import BaseApi
from tests.builder import a from almanach.tests.unit.builder import a
from tests.builder import instance from almanach.tests.unit.builder import instance
class ApiInstanceTest(BaseApi): class ApiInstanceTest(BaseApi):

View File

@ -19,7 +19,7 @@ from hamcrest import equal_to
from hamcrest import has_entries from hamcrest import has_entries
from almanach.core import exception from almanach.core import exception
from tests.api.base_api import BaseApi from almanach.tests.unit.api.base_api import BaseApi
class ApiVolumeTest(BaseApi): class ApiVolumeTest(BaseApi):

View File

@ -20,9 +20,9 @@ from hamcrest import has_key
from hamcrest import has_length from hamcrest import has_length
from almanach.core import exception from almanach.core import exception
from tests.api.base_api import BaseApi from almanach.tests.unit.api.base_api import BaseApi
from tests.builder import a from almanach.tests.unit.builder import a
from tests.builder import volume_type from almanach.tests.unit.builder import volume_type
class ApiVolumeTypeTest(BaseApi): class ApiVolumeTypeTest(BaseApi):

View File

@ -19,8 +19,7 @@ from almanach.api.auth import keystone_auth
from almanach.api.auth import mixed_auth from almanach.api.auth import mixed_auth
from almanach.api.auth import private_key_auth from almanach.api.auth import private_key_auth
from almanach.api import auth_adapter from almanach.api import auth_adapter
from almanach.tests.unit import base
from tests import base
class AuthenticationAdapterTest(base.BaseTestCase): class AuthenticationAdapterTest(base.BaseTestCase):

View File

@ -15,8 +15,8 @@
import mock import mock
from almanach.collector.handlers import instance_handler from almanach.collector.handlers import instance_handler
from tests import base from almanach.tests.unit import base
from tests.builders import notification as builder from almanach.tests.unit.builders import notification as builder
class InstanceHandlerTest(base.BaseTestCase): class InstanceHandlerTest(base.BaseTestCase):

View File

@ -15,8 +15,8 @@
import mock import mock
from almanach.collector.handlers import volume_handler from almanach.collector.handlers import volume_handler
from tests import base from almanach.tests.unit import base
from tests.builders import notification as builder from almanach.tests.unit.builders import notification as builder
class VolumeHandlerTest(base.BaseTestCase): class VolumeHandlerTest(base.BaseTestCase):

View File

@ -15,8 +15,8 @@
import mock import mock
from almanach.collector.handlers import volume_type_handler from almanach.collector.handlers import volume_type_handler
from tests import base from almanach.tests.unit import base
from tests.builders import notification as builder from almanach.tests.unit.builders import notification as builder
class VolumeTypeHandlerTest(base.BaseTestCase): class VolumeTypeHandlerTest(base.BaseTestCase):

View File

@ -16,7 +16,7 @@ import mock
import oslo_messaging import oslo_messaging
from almanach.collector import messaging from almanach.collector import messaging
from tests import base from almanach.tests.unit import base
class MessagingFactoryTest(base.BaseTestCase): class MessagingFactoryTest(base.BaseTestCase):

View File

@ -15,7 +15,7 @@
import mock import mock
from almanach.collector import notification from almanach.collector import notification
from tests import base from almanach.tests.unit import base
class NotificationTest(base.BaseTestCase): class NotificationTest(base.BaseTestCase):

View File

View File

@ -28,12 +28,11 @@ from almanach.core import controller
from almanach.core import exception from almanach.core import exception
from almanach.core import model from almanach.core import model
from almanach.storage.drivers import base_driver from almanach.storage.drivers import base_driver
from almanach.tests.unit import base
from tests import base from almanach.tests.unit.builder import a
from tests.builder import a from almanach.tests.unit.builder import instance
from tests.builder import instance from almanach.tests.unit.builder import volume
from tests.builder import volume from almanach.tests.unit.builder import volume_type
from tests.builder import volume_type
class ControllerTest(base.BaseTestCase): class ControllerTest(base.BaseTestCase):

View File

View File

@ -25,12 +25,11 @@ from hamcrest import contains_inanyorder
from almanach.core import exception from almanach.core import exception
from almanach.core import model from almanach.core import model
from almanach.storage.drivers import mongodb_driver from almanach.storage.drivers import mongodb_driver
from almanach.tests.unit import base
from tests import base from almanach.tests.unit.builder import a
from tests.builder import a from almanach.tests.unit.builder import instance
from tests.builder import instance from almanach.tests.unit.builder import volume
from tests.builder import volume from almanach.tests.unit.builder import volume_type
from tests.builder import volume_type
class MongoDbDriverTest(base.BaseTestCase): class MongoDbDriverTest(base.BaseTestCase):

View File

@ -16,7 +16,7 @@ from almanach.core import exception
from almanach.storage.drivers import mongodb_driver from almanach.storage.drivers import mongodb_driver
from almanach.storage import storage_driver from almanach.storage import storage_driver
from tests import base from almanach.tests.unit import base
class StorageDriverTest(base.BaseTestCase): class StorageDriverTest(base.BaseTestCase):

View File

@ -28,6 +28,8 @@ oslo.config.opts =
console_scripts = console_scripts =
almanach-api = almanach.api.main:main almanach-api = almanach.api.main:main
almanach-collector = almanach.collector.main:main almanach-collector = almanach.collector.main:main
tempest.test_plugins =
almanach_tests = almanach.tests.tempest.plugin:AlmanachTempestPlugin
[nosetests] [nosetests]
no-path-adjustment = 1 no-path-adjustment = 1

View File

@ -8,4 +8,6 @@ sphinxcontrib-httpdomain # BSD
flake8>=2.5.4,<2.6.0 # MIT flake8>=2.5.4,<2.6.0 # MIT
hacking<0.12,>=0.11.0 # Apache-2.0 hacking<0.12,>=0.11.0 # Apache-2.0
testtools>=1.4.0 # MIT testtools>=1.4.0 # MIT
mock>=2.0 # BSD mock>=2.0 # BSD
tempest>=12.1.0 # Apache-2.0
tempest-lib>=0.14.0 # Apache-2.0

View File

@ -7,7 +7,7 @@ deps =
-r{toxinidir}/requirements.txt -r{toxinidir}/requirements.txt
setenv = setenv =
PYTHONPATH = {toxinidir} PYTHONPATH = {toxinidir}
commands = nosetests --tests tests commands = nosetests --tests almanach.tests.unit
[testenv:genconfig] [testenv:genconfig]
commands = oslo-config-generator --namespace almanach --output-file=etc/almanach/almanach.conf commands = oslo-config-generator --namespace almanach --output-file=etc/almanach/almanach.conf