diff --git a/.zuul.yaml b/.zuul.yaml new file mode 100644 index 00000000..ac267c8b --- /dev/null +++ b/.zuul.yaml @@ -0,0 +1,52 @@ +- job: + name: glance_store-dsvm-functional-base + parent: devstack-tox-functional + description: | + Base job for devstack-based functional tests for glance_store + + Can only be used directly if a 'functional' testenv is defined + in tox.ini (which currently is not the case). + required-projects: + - openstack/glance_store + timeout: 4200 + vars: + devstack_localrc: + LIBS_FROM_GIT: glance_store + devstack_services: + # turn off ceilometer + ceilometer-acentral: false + ceilometer-acompute: false + ceilometer-alarm-evaluator: false + ceilometer-alarm-notifier: false + ceilometer-anotification: false + ceilometer-api: false + ceilometer-collector: false + # Hardcode glance_store path so the job can be run on glance patches + zuul_work_dir: src/git.openstack.org/openstack/glance_store + +- job: + name: glance_store-dsvm-functional-filesystem + parent: glance_store-dsvm-functional-base + vars: + tox_envlist: functional-filesystem + +- job: + name: glance_store-dsvm-functional-swift + parent: glance_store-dsvm-functional-base + required-projects: + - openstack/swift + vars: + tox_envlist: functional-swift + devstack_services: + s-account: true + s-container: true + s-object: true + s-proxy: true + devstack_localrc: + ENABLE_IDENTITY_V2: True + +- project: + experimental: + jobs: + - glance_store-dsvm-functional-filesystem + - glance_store-dsvm-functional-swift diff --git a/functional_testing.conf.sample b/functional_testing.conf.sample deleted file mode 100644 index 84989fab..00000000 --- a/functional_testing.conf.sample +++ /dev/null @@ -1,9 +0,0 @@ -[tests] -stores = file,swift - -[admin] -user = admin:admin -key = secretadmin -auth_version = 2 -auth_address = http://localhost:35357/v2.0 -region = RegionOne diff --git a/glance_store/tests/functional/README.rst b/glance_store/tests/functional/README.rst new file mode 100644 index 00000000..7e0bd097 --- /dev/null +++ b/glance_store/tests/functional/README.rst @@ -0,0 +1,78 @@ +=============================== +glance_store functional testing +=============================== + +Writing functional tests for glance_store +----------------------------------------- + +The functional tests verify glance_store against a "live" backend. The tests +are isolated so that a development environment doesn't have to all the backends +available, just the particular backend whose driver the developer is working +on. + +To add tests for a driver: + +1. Create a new module in ``glance_store/tests/functional`` with the driver + name. + +2. Create a submodule ``test_functional_{driver-name}`` containing a class + that inherits from ``glance_store.tests.functional.BaseFunctionalTests``. + The actual tests are in the ``BaseFunctionalTests`` class. The test + classes for each driver do any extra setup/teardown necessary for that + particular driver. (The idea is that all the backends should be able to + pass the same tests.) + +3. Add a testenv to ``tox.ini`` named ``functional-{driver-name}`` so + that tox can run the tests for your driver. (Use the other functional + testenvs as examples.) + +4. If your driver is well-supported by devstack, it shouldn't be too hard + to set up a gate job for the functional tests in ``.zuul.yaml``. (Use + the other jobs defined in that file as examples.) + + +Configuration +------------- + +The functional tests have been designed to work well with devstack so that +we can run them in the gate. Thus the tests expect to find a yaml file +containing valid credentials just like the ``clouds.yaml`` file created by +devstack in the ``/etc/openstack`` directory. The test code knows where +to find it, so if you're using devstack, you should be all set. + +If you are not using devstack you should create a yaml file with the following +format:: + + clouds: + devstack-admin: + auth: + auth_url: https://172.16.132.143/identity + password: example + project_domain_id: default + project_name: admin + user_domain_id: default + username: admin + identity_api_version: '3' + region_name: RegionOne + volume_api_version: '2' + +The clouds.yaml format allows for a set of credentials to be defined for each +named cloud. By default, the tests will use the credentials for the cloud +named **devstack-admin** (that's the cloud shown in the example above). You +can change which cloud is read from ``clouds.yaml`` by exporting the +environment variable ``OS_TEST_GLANCE_STORE_FUNC_TEST_CLOUD`` set to the name +of the cloud you want used. + +Where to put clouds.yaml +------------------------ + +The tests will look for a file named ``clouds.yaml`` in the +following locations (in this order, first found wins): + +* current directory +* ~/.config/openstack +* /etc/openstack + +You may also set the environment variable ``OS_CLIENT_CONFIG_FILE`` +to the absolute pathname of a file and that location will be +inserted at the front of the search list. diff --git a/glance_store/tests/functional/base.py b/glance_store/tests/functional/base.py index d694be18..641c72f4 100644 --- a/glance_store/tests/functional/base.py +++ b/glance_store/tests/functional/base.py @@ -13,13 +13,11 @@ # License for the specific language governing permissions and limitations # under the License. -try: - import configparser as ConfigParser -except ImportError: - from six.moves import configparser as ConfigParser from io import BytesIO +from os import environ import glance_store +import os_client_config from oslo_config import cfg import testtools @@ -37,18 +35,33 @@ class Base(testtools.TestCase): def __init__(self, driver_name, *args, **kwargs): super(Base, self).__init__(*args, **kwargs) self.driver_name = driver_name - self.config = ConfigParser.RawConfigParser() - self.config.read('functional_testing.conf') + # check whether a particular cloud should be used + cloud = environ.get('OS_TEST_GLANCE_STORE_FUNC_TEST_CLOUD', + 'devstack-admin') + creds = os_client_config.OpenStackConfig().get_one_cloud( + cloud=cloud) + auth = creds.get_auth_args() + self.username = auth["username"] + self.password = auth["password"] + self.project_name = auth["project_name"] + self.user_domain_id = auth["user_domain_id"] + self.project_domain_id = auth["project_domain_id"] + self.keystone_version = creds.get_api_version('identity') + self.cinder_version = creds.get_api_version('volume') + self.region_name = creds.get_region_name() + # auth_url in devstack clouds.yaml is unversioned + if auth["auth_url"].endswith('/v3'): + self.auth_url = auth["auth_url"] + else: + self.auth_url = '{}/v3'.format(auth["auth_url"]) + + # finally, load the configuration options glance_store.register_opts(CONF) def setUp(self): super(Base, self).setUp() - stores = self.config.get('tests', 'stores').split(',') - if self.driver_name not in stores: - self.skipTest('Not running %s store tests' % self.driver_name) - CONF.set_override('stores', [self.driver_name], group='glance_store') CONF.set_override('default_store', self.driver_name, diff --git a/glance_store/tests/functional/hooks/gate_hook.sh b/glance_store/tests/functional/hooks/gate_hook.sh deleted file mode 100755 index 026bb20a..00000000 --- a/glance_store/tests/functional/hooks/gate_hook.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash -# -# 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. - -# This script is executed inside gate_hook function in devstack gate. - -# NOTE(NiallBunting) The store to test is passed in here from the -# project config. -GLANCE_STORE_DRIVER=${1:-swift} - -ENABLED_SERVICES+=",key,glance" - -case $GLANCE_STORE_DRIVER in - swift) - ENABLED_SERVICES+=",s-proxy,s-account,s-container,s-object," - ;; -esac - -export GLANCE_STORE_DRIVER - -export ENABLED_SERVICES - -$BASE/new/devstack-gate/devstack-vm-gate.sh diff --git a/glance_store/tests/functional/hooks/post_test_hook.sh b/glance_store/tests/functional/hooks/post_test_hook.sh deleted file mode 100755 index 42ff8e47..00000000 --- a/glance_store/tests/functional/hooks/post_test_hook.sh +++ /dev/null @@ -1,79 +0,0 @@ -#!/bin/bash -xe - -# 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. - -# This script is executed inside post_test_hook function in devstack gate. - -set -xe - -export GLANCE_STORE_DIR="$BASE/new/glance_store" -SCRIPTS_DIR="/usr/os-testr-env/bin/" -GLANCE_STORE_DRIVER=${1:-swift} - -function generate_test_logs { - local path="$1" - # Compress all $path/*.txt files and move the directories holding those - # files to /opt/stack/logs. Files with .log suffix have their - # suffix changed to .txt (so browsers will know to open the compressed - # files and not download them). - if [ -d "$path" ] - then - sudo find $path -iname "*.log" -type f -exec mv {} {}.txt \; -exec gzip -9 {}.txt \; - sudo mv $path/* /opt/stack/logs/ - fi -} - -function generate_testr_results { - if [ -f .testrepository/0 ]; then - # Give job user rights to access tox logs - sudo -H -u "$owner" chmod o+rw . - sudo -H -u "$owner" chmod o+rw -R .testrepository - - if [[ -f ".testrepository/0" ]] ; then - "subunit-1to2" < .testrepository/0 > ./testrepository.subunit - $SCRIPTS_DIR/subunit2html ./testrepository.subunit testr_results.html - gzip -9 ./testrepository.subunit - gzip -9 ./testr_results.html - sudo mv ./*.gz /opt/stack/logs/ - fi - - fi -} - -owner=jenkins - -# Get admin credentials -cd $BASE/new/devstack -source openrc admin admin - -# Go to the glance_store dir -cd $GLANCE_STORE_DIR - -sudo chown -R $owner:stack $GLANCE_STORE_DIR - -sudo cp $GLANCE_STORE_DIR/functional_testing.conf.sample $GLANCE_STORE_DIR/functional_testing.conf - -# Set admin creds -iniset $GLANCE_STORE_DIR/functional_testing.conf admin key $ADMIN_PASSWORD - -# Run tests -echo "Running glance_store functional test suite" -set +e -# Preserve env for OS_ credentials -sudo -E -H -u jenkins tox -e functional-$GLANCE_STORE_DRIVER -EXIT_CODE=$? -set -e - -# Collect and parse result -generate_testr_results -exit $EXIT_CODE diff --git a/glance_store/tests/functional/swift/test_functional_swift.py b/glance_store/tests/functional/swift/test_functional_swift.py index 8133bffc..603a5391 100644 --- a/glance_store/tests/functional/swift/test_functional_swift.py +++ b/glance_store/tests/functional/swift/test_functional_swift.py @@ -18,6 +18,8 @@ import logging import random import time +from keystoneauth1.identity import v3 +from keystoneauth1 import session from oslo_config import cfg import swiftclient @@ -33,27 +35,20 @@ class TestSwift(base.BaseFunctionalTests): def __init__(self, *args, **kwargs): super(TestSwift, self).__init__('swift', *args, **kwargs) - self.auth = self.config.get('admin', 'auth_address') - user = self.config.get('admin', 'user') - self.key = self.config.get('admin', 'key') - self.region = self.config.get('admin', 'region') - - self.tenant, self.username = user.split(':') - CONF.set_override('swift_store_user', - user, + '{1}:{0}'.format(self.username, self.project_name), group='glance_store') CONF.set_override('swift_store_auth_address', - self.auth, + self.auth_url, + group='glance_store') + CONF.set_override('swift_store_auth_version', + self.keystone_version, group='glance_store') CONF.set_override('swift_store_key', - self.key, - group='glance_store') - CONF.set_override('swift_store_create_container_on_put', - True, + self.password, group='glance_store') CONF.set_override('swift_store_region', - self.region, + self.region_name, group='glance_store') CONF.set_override('swift_store_create_container_on_put', True, @@ -70,14 +65,18 @@ class TestSwift(base.BaseFunctionalTests): super(TestSwift, self).setUp() def tearDown(self): + auth = v3.Password(auth_url=self.auth_url, + username=self.username, + password=self.password, + project_name=self.project_name, + user_domain_id=self.user_domain_id, + project_domain_id=self.project_domain_id) + sess = session.Session(auth=auth) + swift = swiftclient.client.Connection(session=sess) + for x in range(1, 4): time.sleep(x) try: - swift = swiftclient.client.Connection(auth_version='2', - user=self.username, - key=self.key, - tenant_name=self.tenant, - authurl=self.auth) _, objects = swift.get_container(self.container) for obj in objects: swift.delete_object(self.container, obj.get('name')) diff --git a/tox.ini b/tox.ini index 986aaeec..c81e3db5 100644 --- a/tox.ini +++ b/tox.ini @@ -45,15 +45,17 @@ commands = python setup.py testr --coverage --testr-args='^(?!.*test.*coverage). [testenv:venv] commands = {posargs} +# See glance_store/tests/functional/README.rst for information on writing or +# running functional tests. [testenv:functional-swift] sitepackages = True setenv = OS_TEST_PATH=./glance_store/tests/functional/swift -commands = python setup.py testr --slowest --testr-args='glance_store.tests.functional.swift' +commands = ostestr --slowest --testr-args='glance_store.tests.functional.swift' [testenv:functional-filesystem] sitepackages = True setenv = OS_TEST_PATH=./glance_store/tests/functional/filesystem -commands = python setup.py testr --slowest --testr-args='glance_store.tests.functional.filesystem' +commands = ostestr --slowest --testr-args='glance_store.tests.functional.filesystem' [flake8] # TODO(dmllr): Analyze or fix the warnings blacklisted below