Adds basic ironicclient functional testing

This moves unit tests to ironicclient/tests/unit and adds a new test
directory at ironicclient/tests/functional.  These are meant to be
functional tests that are run against a living cloud (presumably deployed
by devstack as part of a gating job).  They depend on a test.conf to exist
that contains admin user credentials for said cloud.  This includes a simple
run_functional.sh script that is meant to create that and serve as the entry
point for running the tests from a devstack post_test_hook.

Change-Id: I11570c3e22e4f80b94d0643dca6ed8231217c877
This commit is contained in:
Adam Gandelman
2015-03-05 17:20:03 -08:00
parent fd6f36474b
commit d76862b186
23 changed files with 138 additions and 17 deletions

2
.gitignore vendored
View File

@@ -31,4 +31,4 @@ cover
AUTHORS AUTHORS
ChangeLog ChangeLog
*.sqlite *.sqlite
test.conf

View File

@@ -1,5 +1,5 @@
[DEFAULT] [DEFAULT]
test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} ${PYTHON:-python} -m subunit.run discover -t ./ ./ $LISTOPT $IDOPTION test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} ${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./ironicclient/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

@@ -0,0 +1,92 @@
# -*- coding: utf-8 -*-
#
# Copyright 2015 Hewlett-Packard Development Company, L.P.
# 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.
import ConfigParser
import os
import testtools
import ironicclient
from ironicclient import exc
DEFAULT_CONFIG = os.path.join(os.path.dirname(__file__), 'test.conf')
class TestIronicClient(testtools.TestCase):
def setUp(self):
super(TestIronicClient, self).setUp()
self.client = ironicclient.client.get_client(**self._get_config())
def _get_config(self):
config_file = os.environ.get('IRONICCLIENT_TEST_CONFIG',
DEFAULT_CONFIG)
config = ConfigParser.SafeConfigParser()
if not config.read(config_file):
self.skipTest('Skipping, no test config found @ %s' % config_file)
try:
auth_strategy = config.get('functional', 'auth_strategy')
except ConfigParser.NoOptionError:
auth_strategy = 'keystone'
if auth_strategy not in ['keystone', 'noauth']:
raise self.fail(
'Invalid auth type specified in functional must be one of: '
'keystone, noauth')
out = {}
conf_settings = ['api_version']
if auth_strategy == 'keystone':
conf_settings += ['os_auth_url', 'os_username',
'os_password', 'os_tenant_name']
else:
conf_settings += ['os_auth_token', 'ironic_url']
for c in conf_settings:
try:
out[c] = config.get('functional', c)
except ConfigParser.NoOptionError:
out[c] = None
missing = [k for k, v in out.items() if not v]
if missing:
self.fail('Missing required setting in test.conf (%s) for '
'auth_strategy=%s: %s' %
(config_file, auth_strategy, ','.join(missing)))
return out
def _try_delete_resource(self, resource, id):
mgr = getattr(self.client, resource)
try:
mgr.delete(id)
except exc.NotFound:
pass
def _create_node(self, **kwargs):
if 'driver' not in kwargs:
kwargs['driver'] = 'fake'
node = self.client.node.create(**kwargs)
self.addCleanup(self._try_delete_resource, 'node', node.uuid)
return node
def test_node_list(self):
self.assertTrue(isinstance(self.client.node.list(), list))
def test_node_create_get_delete(self):
node = self._create_node()
self.assertTrue(isinstance(node, ironicclient.v1.node.Node))
got = self.client.node.get(node.uuid)
self.assertTrue(isinstance(got, ironicclient.v1.node.Node))
self.client.node.delete(node.uuid)
self.assertRaises(exc.NotFound, self.client.node.get, node.uuid)

View File

View File

@@ -16,7 +16,7 @@ import fixtures
from ironicclient.client import get_client from ironicclient.client import get_client
from ironicclient import exc from ironicclient import exc
from ironicclient.tests import utils from ironicclient.tests.unit import utils
def fake_get_ksclient(**kwargs): def fake_get_ksclient(**kwargs):

View File

@@ -21,7 +21,7 @@ import six
from ironicclient.common import http from ironicclient.common import http
from ironicclient import exc from ironicclient import exc
from ironicclient.tests import utils from ironicclient.tests.unit import utils
HTTP_CLASS = six.moves.http_client.HTTPConnection HTTP_CLASS = six.moves.http_client.HTTPConnection

View File

@@ -12,7 +12,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.
from ironicclient.tests import utils from ironicclient.tests.unit import utils
module_str = 'ironicclient' module_str = 'ironicclient'

View File

@@ -30,8 +30,8 @@ from testtools import matchers
from ironicclient import exc from ironicclient import exc
from ironicclient import shell as ironic_shell from ironicclient import shell as ironic_shell
from ironicclient.tests import keystone_client_fixtures from ironicclient.tests.unit import keystone_client_fixtures
from ironicclient.tests import utils from ironicclient.tests.unit import utils
FAKE_ENV = {'OS_USERNAME': 'username', FAKE_ENV = {'OS_USERNAME': 'username',
'OS_PASSWORD': 'password', 'OS_PASSWORD': 'password',

View File

@@ -19,7 +19,7 @@ import mock
from ironicclient.common import utils from ironicclient.common import utils
from ironicclient import exc from ironicclient import exc
from ironicclient.tests import utils as test_utils from ironicclient.tests.unit import utils as test_utils
class UtilsTest(test_utils.BaseTestCase): class UtilsTest(test_utils.BaseTestCase):

View File

View File

@@ -20,7 +20,7 @@ import copy
import testtools import testtools
from testtools.matchers import HasLength from testtools.matchers import HasLength
from ironicclient.tests import utils from ironicclient.tests.unit import utils
import ironicclient.v1.chassis import ironicclient.v1.chassis
CHASSIS = {'id': 42, CHASSIS = {'id': 42,

View File

@@ -17,7 +17,7 @@
import mock import mock
from ironicclient.openstack.common import cliutils from ironicclient.openstack.common import cliutils
from ironicclient.tests import utils from ironicclient.tests.unit import utils
import ironicclient.v1.chassis_shell as c_shell import ironicclient.v1.chassis_shell as c_shell

View File

@@ -20,7 +20,7 @@ import testtools
from testtools import matchers from testtools import matchers
from ironicclient import exc from ironicclient import exc
from ironicclient.tests import utils from ironicclient.tests.unit import utils
from ironicclient.v1 import driver from ironicclient.v1 import driver

View File

@@ -17,7 +17,7 @@
import mock import mock
from ironicclient.openstack.common import cliutils from ironicclient.openstack.common import cliutils
from ironicclient.tests import utils from ironicclient.tests.unit import utils
import ironicclient.v1.driver_shell as d_shell import ironicclient.v1.driver_shell as d_shell

View File

@@ -22,7 +22,7 @@ import testtools
from testtools.matchers import HasLength from testtools.matchers import HasLength
from ironicclient import exc from ironicclient import exc
from ironicclient.tests import utils from ironicclient.tests.unit import utils
from ironicclient.v1 import node from ironicclient.v1 import node
NODE1 = {'id': 123, NODE1 = {'id': 123,

View File

@@ -19,7 +19,7 @@ import mock
from ironicclient.common import utils as commonutils from ironicclient.common import utils as commonutils
from ironicclient.openstack.common.apiclient import exceptions from ironicclient.openstack.common.apiclient import exceptions
from ironicclient.openstack.common import cliutils from ironicclient.openstack.common import cliutils
from ironicclient.tests import utils from ironicclient.tests.unit import utils
import ironicclient.v1.node_shell as n_shell import ironicclient.v1.node_shell as n_shell

View File

@@ -20,7 +20,7 @@ import copy
import testtools import testtools
from testtools.matchers import HasLength from testtools.matchers import HasLength
from ironicclient.tests import utils from ironicclient.tests.unit import utils
import ironicclient.v1.port import ironicclient.v1.port
PORT = {'id': 987, PORT = {'id': 987,

View File

@@ -18,7 +18,7 @@ import mock
from ironicclient.common import utils as commonutils from ironicclient.common import utils as commonutils
from ironicclient.openstack.common import cliutils from ironicclient.openstack.common import cliutils
from ironicclient.tests import utils from ironicclient.tests.unit import utils
import ironicclient.v1.port_shell as p_shell import ironicclient.v1.port_shell as p_shell

26
tools/run_functional.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/bin/bash
FUNC_TEST_DIR=$(dirname $0)/../ironicclient/tests/functional/
CONFIG_FILE=$FUNC_TEST_DIR/test.conf
if [[ -n "$OS_AUTH_TOKEN" ]] && [[ -n "$IRONIC_URL" ]]; then
cat <<END >$CONFIG_FILE
[functional]
api_version = 1
auth_strategy=noauth
os_auth_token=$OS_AUTH_TOKEN
ironic_url=$IRONIC_URL
END
else
cat <<END >$CONFIG_FILE
[functional]
api_version = 1
os_auth_url=$OS_AUTH_URL
os_username=$OS_USERNAME
os_password=$OS_PASSWORD
os_tenant_name=$OS_TENANT_NAME
os_service_type=baremetal
os_endpoint_type=public
END
fi
tox -e functional

View File

@@ -28,6 +28,9 @@ commands =
[testenv:venv] [testenv:venv]
commands = {posargs} commands = {posargs}
[testenv:functional]
setenv = OS_TEST_PATH=./ironicclient/tests/functional
[flake8] [flake8]
ignore = E126,E127,E128 ignore = E126,E127,E128
builtins = _ builtins = _