diff options
| -rw-r--r-- | README.rst | 13 | ||||
| -rw-r--r-- | functional_creds.conf.sample | 8 | ||||
| -rw-r--r-- | novaclient/tests/functional/base.py | 126 | ||||
| -rwxr-xr-x | novaclient/tests/functional/hooks/post_test_hook.sh | 17 | ||||
| -rw-r--r-- | novaclient/tests/functional/test_instances.py | 42 | ||||
| -rw-r--r-- | novaclient/tests/functional/test_volumes_api.py | 11 | ||||
| -rw-r--r-- | requirements.txt | 4 | ||||
| -rw-r--r-- | test-requirements.txt | 2 |
8 files changed, 155 insertions, 68 deletions
@@ -77,3 +77,16 @@ To use with nova, with keystone as the authentication system:: [...] >>> nt.keypairs.list() [...] + +Testing +------- + +There are multiple test targets that can be run to validate the code. + +* tox -e pep8 - style guidelines enforcement +* tox -e py27 - traditional unit testing +* tox -e functional - live functional testing against an existing + openstack + +Functional testing assumes the existance of a functional_creds.conf in +the root directory. See the .sample for example format. diff --git a/functional_creds.conf.sample b/functional_creds.conf.sample new file mode 100644 index 00000000..081a7368 --- /dev/null +++ b/functional_creds.conf.sample @@ -0,0 +1,8 @@ +# Credentials for functional testing +[auth] +uri = http://10.42.0.50:5000/v2.0 + +[admin] +user = admin +tenant = admin +pass = secrete diff --git a/novaclient/tests/functional/base.py b/novaclient/tests/functional/base.py index 27015bda..ac795325 100644 --- a/novaclient/tests/functional/base.py +++ b/novaclient/tests/functional/base.py @@ -10,12 +10,47 @@ # License for the specific language governing permissions and limitations # under the License. +import ConfigParser import os -from tempest_lib.cli import base +import fixtures +import tempest_lib.cli.base +import testtools +import novaclient.client -class ClientTestBase(base.ClientTestBase): + +# The following are simple filter functions that filter our available +# image / flavor list so that they can be used in standard testing. +def pick_flavor(flavors): + """Given a flavor list pick a reasonable one.""" + for flavor in flavors: + if flavor.name == 'm1.tiny': + return flavor + for flavor in flavors: + if flavor.name == 'm1.small': + return flavor + raise NoFlavorException() + + +def pick_image(images): + for image in images: + if image.name.startswith('cirros') and image.name.endswith('-uec'): + return image + raise NoImageException() + + +class NoImageException(Exception): + """We couldn't find an acceptable image.""" + pass + + +class NoFlavorException(Exception): + """We couldn't find an acceptable flavor.""" + pass + + +class ClientTestBase(testtools.TestCase): """ This is a first pass at a simple read only python-novaclient test. This only exercises client commands that are read only. @@ -27,18 +62,89 @@ class ClientTestBase(base.ClientTestBase): * initially just check return codes, and later test command outputs """ - def _get_clients(self): + log_format = ('%(asctime)s %(process)d %(levelname)-8s ' + '[%(name)s] %(message)s') + + def setUp(self): + super(ClientTestBase, self).setUp() + + test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0) + try: + test_timeout = int(test_timeout) + except ValueError: + test_timeout = 0 + if test_timeout > 0: + self.useFixture(fixtures.Timeout(test_timeout, gentle=True)) + + if (os.environ.get('OS_STDOUT_CAPTURE') == 'True' or + os.environ.get('OS_STDOUT_CAPTURE') == '1'): + stdout = self.useFixture(fixtures.StringStream('stdout')).stream + self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout)) + if (os.environ.get('OS_STDERR_CAPTURE') == 'True' or + os.environ.get('OS_STDERR_CAPTURE') == '1'): + stderr = self.useFixture(fixtures.StringStream('stderr')).stream + self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr)) + + if (os.environ.get('OS_LOG_CAPTURE') != 'False' and + os.environ.get('OS_LOG_CAPTURE') != '0'): + self.useFixture(fixtures.LoggerFixture(nuke_handlers=False, + format=self.log_format, + level=None)) + + # Collecting of credentials: + # + # Support the existence of a functional_creds.conf for + # testing. This makes it possible to use a config file. + # + # Those variables can be overridden by environmental variables + # as well to support existing users running these the old + # way. We should deprecate that. + + # TODO(sdague): while we collect this information in + # tempest-lib, we do it in a way that's not available for top + # level tests. Long term this probably needs to be in the base + # class. + user = os.environ.get('OS_USERNAME') + passwd = os.environ.get('OS_PASSWORD') + tenant = os.environ.get('OS_TENANT_NAME') + auth_url = os.environ.get('OS_AUTH_URL') + + config = ConfigParser.RawConfigParser() + if config.read('functional_creds.conf'): + # the OR pattern means the environment is preferred for + # override + user = user or config.get('admin', 'user') + passwd = passwd or config.get('admin', 'pass') + tenant = tenant or config.get('admin', 'tenant') + auth_url = auth_url or config.get('auth', 'uri') + + # TODO(sdague): we made a lot of fun of the glanceclient team + # for version as int in first parameter. I guess we know where + # they copied it from. + self.client = novaclient.client.Client( + 2, user, passwd, tenant, + auth_url=auth_url) + + # pick some reasonable flavor / image combo + self.flavor = pick_flavor(self.client.flavors.list()) + self.image = pick_image(self.client.images.list()) + + # create a CLI client in case we'd like to do CLI + # testing. tempest_lib does this realy weird thing where it + # builds a giant factory of all the CLIs that it knows + # about. Eventually that should really be unwound into + # something more sensible. cli_dir = os.environ.get( 'OS_NOVACLIENT_EXEC_DIR', os.path.join(os.path.abspath('.'), '.tox/functional/bin')) - return base.CLIClient( - username=os.environ.get('OS_USERNAME'), - password=os.environ.get('OS_PASSWORD'), - tenant_name=os.environ.get('OS_TENANT_NAME'), - uri=os.environ.get('OS_AUTH_URL'), + self.cli_clients = tempest_lib.cli.base.CLIClient( + username=user, + password=passwd, + tenant_name=tenant, + uri=auth_url, cli_dir=cli_dir) def nova(self, *args, **kwargs): - return self.clients.nova(*args, - **kwargs) + return self.cli_clients.nova(*args, + **kwargs) diff --git a/novaclient/tests/functional/hooks/post_test_hook.sh b/novaclient/tests/functional/hooks/post_test_hook.sh index e9e35b24..5878ace9 100755 --- a/novaclient/tests/functional/hooks/post_test_hook.sh +++ b/novaclient/tests/functional/hooks/post_test_hook.sh @@ -28,15 +28,28 @@ function generate_testr_results { export NOVACLIENT_DIR="$BASE/new/python-novaclient" +sudo chown -R jenkins:stack $NOVACLIENT_DIR + # Get admin credentials cd $BASE/new/devstack source openrc admin admin +# pass the appropriate variables via a config file +CREDS_FILE=$NOVACLIENT_DIR/functional_creds.conf +cat <<EOF > $CREDS_FILE +# Credentials for functional testing +[auth] +uri = $OS_AUTH_URL + +[admin] +user = $OS_USERNAME +tenant = $OS_TENANT_NAME +pass = $OS_PASSWORD + +EOF # Go to the novaclient dir cd $NOVACLIENT_DIR -sudo chown -R jenkins:stack $NOVACLIENT_DIR - # Run tests echo "Running novaclient functional test suite" set +e diff --git a/novaclient/tests/functional/test_instances.py b/novaclient/tests/functional/test_instances.py index c963a6b7..8df28d13 100644 --- a/novaclient/tests/functional/test_instances.py +++ b/novaclient/tests/functional/test_instances.py @@ -10,33 +10,12 @@ # License for the specific language governing permissions and limitations # under the License. -import os import time import uuid -import novaclient.client from novaclient.tests.functional import base -# TODO(sdague): content that probably should be in utils, also throw -# Exceptions when they fail. -def pick_flavor(flavors): - """Given a flavor list pick a reasonable one.""" - for flavor in flavors: - if flavor.name == 'm1.tiny': - return flavor - - for flavor in flavors: - if flavor.name == 'm1.small': - return flavor - - -def pick_image(images): - for image in images: - if image.name.startswith('cirros') and image.name.endswith('-uec'): - return image - - def volume_id_from_cli_create(output): """Scrape the volume id out of the 'volume create' command @@ -67,27 +46,6 @@ def volume_at_status(output, volume_id, status): class TestInstanceCLI(base.ClientTestBase): - def setUp(self): - super(TestInstanceCLI, self).setUp() - # TODO(sdague): while we collect this information in - # tempest-lib, we do it in a way that's not available for top - # level tests. Long term this probably needs to be in the base - # class. - user = os.environ['OS_USERNAME'] - passwd = os.environ['OS_PASSWORD'] - tenant = os.environ['OS_TENANT_NAME'] - auth_url = os.environ['OS_AUTH_URL'] - - # TODO(sdague): we made a lot of fun of the glanceclient team - # for version as int in first parameter. I guess we know where - # they copied it from. - self.client = novaclient.client.Client( - 2, user, passwd, tenant, - auth_url=auth_url) - - # pick some reasonable flavor / image combo - self.flavor = pick_flavor(self.client.flavors.list()) - self.image = pick_image(self.client.images.list()) def test_attach_volume(self): """Test we can attach a volume via the cli. diff --git a/novaclient/tests/functional/test_volumes_api.py b/novaclient/tests/functional/test_volumes_api.py index e427c2e2..38c63bbf 100644 --- a/novaclient/tests/functional/test_volumes_api.py +++ b/novaclient/tests/functional/test_volumes_api.py @@ -10,13 +10,11 @@ # License for the specific language governing permissions and limitations # under the License. -import os import time import uuid import six.moves -from novaclient import client from novaclient import exceptions from novaclient.tests.functional import base @@ -35,15 +33,6 @@ def wait_for_delete(test, name, thing, get_func): class TestVolumesAPI(base.ClientTestBase): - def setUp(self): - super(TestVolumesAPI, self).setUp() - user = os.environ['OS_USERNAME'] - passwd = os.environ['OS_PASSWORD'] - tenant = os.environ['OS_TENANT_NAME'] - auth_url = os.environ['OS_AUTH_URL'] - - self.client = client.Client(2, user, passwd, tenant, auth_url=auth_url) - def test_volumes_snapshots_types_create_get_list_delete(self): # Create a volume volume = self.client.volumes.create(1) diff --git a/requirements.txt b/requirements.txt index bc729cf8..324426b3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,8 +4,8 @@ pbr>=0.6,!=0.7,<1.0 argparse iso8601>=0.1.9 -oslo.i18n>=1.3.0 # Apache-2.0 -oslo.serialization>=1.2.0 # Apache-2.0 +oslo.i18n<1.6.0,>=1.5.0 # Apache-2.0 +oslo.serialization<1.5.0,>=1.4.0 # Apache-2.0 oslo.utils>=1.2.0 # Apache-2.0 PrettyTable>=0.7,<0.8 requests>=2.2.0,!=2.4.0 diff --git a/test-requirements.txt b/test-requirements.txt index acdbc244..4e98decc 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -7,7 +7,7 @@ coverage>=3.6 discover fixtures>=0.3.14 keyring>=2.1,!=3.3 -mock>=1.0 +mock<1.1.0,>=1.0 requests-mock>=0.5.1 # Apache-2.0 sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3 oslosphinx>=2.2.0 # Apache-2.0 |
