Merge "Adds scenario for hotplug nic in network_basic_ops"
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 0f18f5e..ee2da40 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -105,6 +105,10 @@
# value)
#catalog_type=baremetal
+# The endpoint type to use for the baremetal provisioning
+# service. (string value)
+#endpoint_type=publicURL
+
[boto]
@@ -165,6 +169,11 @@
# value)
#cli_dir=/usr/local/bin
+# Whether the tempest run location has access to the *-manage
+# commands. In a pure blackbox environment it will not.
+# (boolean value)
+#has_manage=true
+
# Number of seconds to wait on a CLI timeout (integer value)
#timeout=15
@@ -350,6 +359,10 @@
# iSCSI volumes (boolean value)
#block_migrate_cinder_iscsi=false
+# Enable VNC console. This configuration value should be same
+# as [nova.vnc]->vnc_enabled in nova.conf (boolean value)
+#vnc_console=false
+
[dashboard]
@@ -373,6 +386,10 @@
# Catalog type of the data processing service. (string value)
#catalog_type=data_processing
+# The endpoint type to use for the data processing service.
+# (string value)
+#endpoint_type=publicURL
+
[debug]
@@ -622,6 +639,9 @@
# creating containers (string value)
#operator_role=Member
+# User role that has reseller admin (string value)
+#reseller_admin_role=ResellerAdmin
+
[object-storage-feature-enabled]
@@ -811,6 +831,10 @@
# Catalog type of the Telemetry service. (string value)
#catalog_type=metering
+# The endpoint type to use for the telemetry service. (string
+# value)
+#endpoint_type=publicURL
+
[volume]
diff --git a/requirements.txt b/requirements.txt
index 8573a2e..0bddca3 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,6 +1,5 @@
-pbr>=0.5.21,<1.0
+pbr>=0.6,<1.0
anyjson>=0.3.3
-nose
httplib2>=0.7.5
jsonschema>=2.0.0,<3.0.0
testtools>=0.9.34
@@ -9,18 +8,18 @@
paramiko>=1.9.0
netaddr>=0.7.6
python-glanceclient>=0.9.0
-python-keystoneclient>=0.4.2
+python-keystoneclient>=0.6.0
python-novaclient>=2.15.0
-python-neutronclient>=2.3.3,<3
+python-neutronclient>=2.3.4,<3
python-cinderclient>=1.0.6
python-heatclient>=0.2.3
-python-savannaclient>=0.4.1
-python-swiftclient>=1.5
+python-savannaclient>=0.5.0
+python-swiftclient>=1.6
testresources>=0.2.4
keyring>=1.6.1,<2.0,>=2.1
-testrepository>=0.0.17
+testrepository>=0.0.18
oslo.config>=1.2.0
-six>=1.4.1
+six>=1.5.2
iso8601>=0.1.8
fixtures>=0.3.14
testscenarios>=0.4
diff --git a/run_tempest.sh b/run_tempest.sh
index f6c330d..bdd1f69 100755
--- a/run_tempest.sh
+++ b/run_tempest.sh
@@ -53,12 +53,12 @@
-u|--update) update=1;;
-d|--debug) debug=1;;
-C|--config) config_file=$2; shift;;
- -s|--smoke) testrargs+="smoke"; noseargs+="--attr=type=smoke";;
+ -s|--smoke) testrargs+="smoke";;
-t|--serial) serial=1;;
-l|--logging) logging=1;;
-L|--logging-config) logging_config=$2; shift;;
--) [ "yes" == "$first_uu" ] || testrargs="$testrargs $1"; first_uu=no ;;
- *) testrargs="$testrargs $1"; noseargs+=" $1" ;;
+ *) testrargs+="$testrargs $1";;
esac
shift
done
@@ -110,22 +110,6 @@
fi
}
-function run_tests_nose {
- export NOSE_WITH_OPENSTACK=1
- export NOSE_OPENSTACK_COLOR=1
- export NOSE_OPENSTACK_RED=15.00
- export NOSE_OPENSTACK_YELLOW=3.00
- export NOSE_OPENSTACK_SHOW_ELAPSED=1
- export NOSE_OPENSTACK_STDOUT=1
- export TEMPEST_PY26_NOSE_COMPAT=1
- if [[ "x$noseargs" =~ "tempest" ]]; then
- noseargs="$testrargs"
- else
- noseargs="$noseargs tempest"
- fi
- ${wrapper} nosetests $noseargs
-}
-
if [ $never_venv -eq 0 ]
then
# Remove the virtual environment if --force used
@@ -156,12 +140,7 @@
fi
fi
-py_version=`${wrapper} python --version 2>&1`
-if [[ $py_version =~ "2.6" ]] ; then
- run_tests_nose
-else
- run_tests
-fi
+run_tests
retval=$?
exit $retval
diff --git a/run_tests.sh b/run_tests.sh
index cb6a5df..a12bf46 100755
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -54,7 +54,7 @@
-c|--coverage) coverage=1;;
-t|--serial) serial=1;;
--) [ "yes" == "$first_uu" ] || testrargs="$testrargs $1"; first_uu=no ;;
- *) testrargs="$testrargs $1"; noseargs+=" $1" ;;
+ *) testrargs="$testrargs $1";;
esac
shift
done
@@ -84,6 +84,11 @@
return $?
fi
+ if [ $coverage -eq 1 ]; then
+ ${wrapper} python setup.py test --coverage
+ return $?
+ fi
+
if [ $serial -eq 1 ]; then
${wrapper} testr run --subunit $testrargs | ${wrapper} subunit-2to1 | ${wrapper} tools/colorizer.py
else
@@ -137,10 +142,6 @@
exit
fi
-if [ $coverage -eq 1 ]; then
- $testrargs = "--coverage $testrargs"
-fi
-
run_tests
retval=$?
diff --git a/tempest/api/compute/admin/test_aggregates.py b/tempest/api/compute/admin/test_aggregates.py
index 08d8a0d..4818aa6 100644
--- a/tempest/api/compute/admin/test_aggregates.py
+++ b/tempest/api/compute/admin/test_aggregates.py
@@ -47,7 +47,7 @@
resp, aggregate = self.client.create_aggregate(name=aggregate_name)
self.assertEqual(200, resp.status)
self.assertEqual(aggregate_name, aggregate['name'])
- self.assertEqual(None, aggregate['availability_zone'])
+ self.assertIsNone(aggregate['availability_zone'])
resp, _ = self.client.delete_aggregate(aggregate['id'])
self.assertEqual(200, resp.status)
@@ -175,7 +175,7 @@
self.assertEqual(1, len(aggs))
agg = aggs[0]
self.assertEqual(aggregate_name, agg['name'])
- self.assertEqual(None, agg['availability_zone'])
+ self.assertIsNone(agg['availability_zone'])
self.assertIn(self.host, agg['hosts'])
@attr(type='gate')
@@ -190,7 +190,7 @@
resp, body = self.client.get_aggregate(aggregate['id'])
self.assertEqual(aggregate_name, body['name'])
- self.assertEqual(None, body['availability_zone'])
+ self.assertIsNone(body['availability_zone'])
self.assertIn(self.host, body['hosts'])
@attr(type='gate')
diff --git a/tempest/api/compute/admin/test_servers.py b/tempest/api/compute/admin/test_servers.py
index 8a5f1a5..3b7f221 100644
--- a/tempest/api/compute/admin/test_servers.py
+++ b/tempest/api/compute/admin/test_servers.py
@@ -175,6 +175,16 @@
rebuilt_image_id = server['image']['id']
self.assertEqual(self.image_ref_alt, rebuilt_image_id)
+ @test.attr(type='gate')
+ def test_reset_network_inject_network_info(self):
+ # Reset Network of a Server
+ resp, server = self.create_test_server(wait_until='ACTIVE')
+ resp, server_body = self.client.reset_network(server['id'])
+ self.assertEqual(202, resp.status)
+ # Inject the Network Info into Server
+ resp, server_body = self.client.inject_network_info(server['id'])
+ self.assertEqual(202, resp.status)
+
class ServersAdminTestXML(ServersAdminTestJSON):
_host_key = (
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 72bb723..9162926 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -303,6 +303,8 @@
class BaseV3ComputeTest(BaseComputeTest):
+ _interface = "json"
+
@classmethod
def setUpClass(cls):
# By default compute tests do not create network resources
diff --git a/tempest/api/compute/security_groups/test_security_group_rules_negative.py b/tempest/api/compute/security_groups/test_security_group_rules_negative.py
index 680bc2f..9c9e72c 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules_negative.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules_negative.py
@@ -13,8 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import testtools
-
from tempest.api.compute.security_groups import base
from tempest.common.utils import data_utils
from tempest import config
@@ -24,6 +22,13 @@
CONF = config.CONF
+def not_existing_id():
+ if CONF.service_available.neutron:
+ return data_utils.rand_uuid()
+ else:
+ return data_utils.rand_int_id(start=999)
+
+
class SecurityGroupRulesNegativeTestJSON(base.BaseSecurityGroupsTest):
_interface = 'json'
@@ -32,14 +37,12 @@
super(SecurityGroupRulesNegativeTestJSON, cls).setUpClass()
cls.client = cls.security_groups_client
- @test.skip_because(bug="1182384",
- condition=CONF.service_available.neutron)
@test.attr(type=['negative', 'smoke'])
def test_create_security_group_rule_with_non_existent_id(self):
# Negative test: Creation of Security Group rule should FAIL
# with non existent Parent group id
# Adding rules to the non existent Security Group id
- parent_group_id = data_utils.rand_int_id(start=999)
+ parent_group_id = not_existing_id()
ip_protocol = 'tcp'
from_port = 22
to_port = 22
@@ -47,8 +50,6 @@
self.client.create_security_group_rule,
parent_group_id, ip_protocol, from_port, to_port)
- @testtools.skipIf(CONF.service_available.neutron,
- "Neutron not check the security_group_id")
@test.attr(type=['negative', 'smoke'])
def test_create_security_group_rule_with_invalid_id(self):
# Negative test: Creation of Security Group rule should FAIL
@@ -146,13 +147,11 @@
self.client.create_security_group_rule,
secgroup_id, ip_protocol, from_port, to_port)
- @test.skip_because(bug="1182384",
- condition=CONF.service_available.neutron)
@test.attr(type=['negative', 'smoke'])
def test_delete_security_group_rule_with_non_existent_id(self):
# Negative test: Deletion of Security Group rule should be FAIL
# with non existent id
- non_existent_rule_id = data_utils.rand_int_id(start=999)
+ non_existent_rule_id = not_existing_id()
self.assertRaises(exceptions.NotFound,
self.client.delete_security_group_rule,
non_existent_rule_id)
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index 9cdac55..c8ab5ae 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -48,6 +48,7 @@
def _create_server_get_interfaces(self):
resp, server = self.create_test_server(wait_until='ACTIVE')
resp, ifs = self.client.list_interfaces(server['id'])
+ self.assertEqual(200, resp.status)
resp, body = self.client.wait_for_interface_status(
server['id'], ifs[0]['port_id'], 'ACTIVE')
ifs[0]['port_state'] = body['port_state']
@@ -55,6 +56,7 @@
def _test_create_interface(self, server):
resp, iface = self.client.create_interface(server['id'])
+ self.assertEqual(200, resp.status)
resp, iface = self.client.wait_for_interface_status(
server['id'], iface['port_id'], 'ACTIVE')
self._check_interface(iface)
@@ -64,6 +66,7 @@
network_id = ifs[0]['net_id']
resp, iface = self.client.create_interface(server['id'],
network_id=network_id)
+ self.assertEqual(200, resp.status)
resp, iface = self.client.wait_for_interface_status(
server['id'], iface['port_id'], 'ACTIVE')
self._check_interface(iface, network_id=network_id)
@@ -73,12 +76,14 @@
iface = ifs[0]
resp, _iface = self.client.show_interface(server['id'],
iface['port_id'])
+ self.assertEqual(200, resp.status)
self.assertEqual(iface, _iface)
def _test_delete_interface(self, server, ifs):
# NOTE(danms): delete not the first or last, but one in the middle
iface = ifs[1]
- self.client.delete_interface(server['id'], iface['port_id'])
+ resp, _ = self.client.delete_interface(server['id'], iface['port_id'])
+ self.assertEqual(202, resp.status)
_ifs = self.client.list_interfaces(server['id'])[1]
start = int(time.time())
@@ -123,6 +128,33 @@
_ifs = self._test_delete_interface(server, ifs)
self.assertEqual(len(ifs) - 1, len(_ifs))
+ @attr(type='gate')
+ def test_add_remove_fixed_ip(self):
+ # Add and Remove the fixed IP to server.
+ server, ifs = self._create_server_get_interfaces()
+ interface_count = len(ifs)
+ self.assertTrue(interface_count > 0)
+ self._check_interface(ifs[0])
+ network_id = ifs[0]['net_id']
+ resp, body = self.client.add_fixed_ip(server['id'],
+ network_id)
+ self.assertEqual(202, resp.status)
+ # Remove the fixed IP from server.
+ server_resp, server_detail = self.os.servers_client.get_server(
+ server['id'])
+ # Get the Fixed IP from server.
+ fixed_ip = None
+ for ip_set in server_detail['addresses']:
+ for ip in server_detail['addresses'][ip_set]:
+ if ip['OS-EXT-IPS:type'] == 'fixed':
+ fixed_ip = ip['addr']
+ break
+ if fixed_ip is not None:
+ break
+ resp, body = self.client.remove_fixed_ip(server['id'],
+ fixed_ip)
+ self.assertEqual(202, resp.status)
+
class AttachInterfacesTestXML(AttachInterfacesTestJSON):
_interface = 'xml'
diff --git a/tempest/api/compute/servers/test_delete_server.py b/tempest/api/compute/servers/test_delete_server.py
index ec40ce0..7007521 100644
--- a/tempest/api/compute/servers/test_delete_server.py
+++ b/tempest/api/compute/servers/test_delete_server.py
@@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+import testtools
+
from tempest.api.compute import base
from tempest import config
from tempest import test
@@ -36,6 +38,7 @@
resp, server = self.create_test_server(wait_until='BUILD')
resp, _ = self.client.delete_server(server['id'])
self.assertEqual('204', resp['status'])
+ self.client.wait_for_server_termination(server['id'])
@test.attr(type='gate')
def test_delete_active_server(self):
@@ -43,6 +46,7 @@
resp, server = self.create_test_server(wait_until='ACTIVE')
resp, _ = self.client.delete_server(server['id'])
self.assertEqual('204', resp['status'])
+ self.client.wait_for_server_termination(server['id'])
@test.attr(type='gate')
def test_delete_server_while_in_shutoff_state(self):
@@ -52,6 +56,7 @@
self.client.wait_for_server_status(server['id'], 'SHUTOFF')
resp, _ = self.client.delete_server(server['id'])
self.assertEqual('204', resp['status'])
+ self.client.wait_for_server_termination(server['id'])
@test.attr(type='gate')
def test_delete_server_while_in_pause_state(self):
@@ -61,6 +66,7 @@
self.client.wait_for_server_status(server['id'], 'PAUSED')
resp, _ = self.client.delete_server(server['id'])
self.assertEqual('204', resp['status'])
+ self.client.wait_for_server_termination(server['id'])
@test.attr(type='gate')
def test_delete_server_while_in_shelved_state(self):
@@ -79,6 +85,20 @@
'SHELVED')
resp, _ = self.client.delete_server(server['id'])
self.assertEqual('204', resp['status'])
+ self.client.wait_for_server_termination(server['id'])
+
+ @testtools.skipIf(not CONF.compute_feature_enabled.resize,
+ 'Resize not available.')
+ @test.attr(type='gate')
+ def test_delete_server_while_in_verify_resize_state(self):
+ # Delete a server while it's VM state is VERIFY_RESIZE
+ resp, server = self.create_test_server(wait_until='ACTIVE')
+ resp, body = self.client.resize(server['id'], self.flavor_ref_alt)
+ self.assertEqual(202, resp.status)
+ self.client.wait_for_server_status(server['id'], 'VERIFY_RESIZE')
+ resp, _ = self.client.delete_server(server['id'])
+ self.assertEqual('204', resp['status'])
+ self.client.wait_for_server_termination(server['id'])
class DeleteServersAdminTestJSON(base.BaseV2ComputeAdminTest):
@@ -103,6 +123,8 @@
self.assertEqual(server['status'], 'ERROR')
resp, _ = self.non_admin_client.delete_server(server['id'])
self.assertEqual('204', resp['status'])
+ self.servers_client.wait_for_server_termination(server['id'],
+ ignore_error=True)
@test.attr(type='gate')
def test_admin_delete_servers_of_others(self):
diff --git a/tempest/api/compute/servers/test_list_servers_negative.py b/tempest/api/compute/servers/test_list_servers_negative.py
index a0aefd8..72af51b 100644
--- a/tempest/api/compute/servers/test_list_servers_negative.py
+++ b/tempest/api/compute/servers/test_list_servers_negative.py
@@ -15,6 +15,8 @@
import datetime
+from six import moves
+
from tempest.api.compute import base
from tempest import exceptions
from tempest.test import attr
@@ -36,7 +38,7 @@
cls.existing_fixtures = []
cls.deleted_fixtures = []
cls.start_time = datetime.datetime.utcnow()
- for x in xrange(2):
+ for x in moves.xrange(2):
resp, srv = cls.create_test_server()
cls.existing_fixtures.append(srv)
diff --git a/tempest/api/compute/servers/test_server_rescue.py b/tempest/api/compute/servers/test_server_rescue.py
index 0bf604c..826317d 100644
--- a/tempest/api/compute/servers/test_server_rescue.py
+++ b/tempest/api/compute/servers/test_server_rescue.py
@@ -15,8 +15,7 @@
from tempest.api.compute import base
from tempest.common.utils import data_utils
-from tempest import exceptions
-from tempest.test import attr
+from tempest import test
class ServerRescueTestJSON(base.BaseV2ComputeTest):
@@ -26,7 +25,6 @@
def setUpClass(cls):
cls.set_network_resources(network=True, subnet=True, router=True)
super(ServerRescueTestJSON, cls).setUpClass()
- cls.device = 'vdf'
# Floating IP creation
resp, body = cls.floating_ips_client.create_floating_ip()
@@ -54,14 +52,6 @@
cls.password = server['adminPass']
cls.servers_client.wait_for_server_status(cls.server_id, 'ACTIVE')
- # Server for negative tests
- cls.rescue_id = resc_server['id']
- cls.rescue_password = resc_server['adminPass']
-
- cls.servers_client.rescue_server(
- cls.rescue_id, adminPass=cls.rescue_password)
- cls.servers_client.wait_for_server_status(cls.rescue_id, 'RESCUE')
-
def setUp(self):
super(ServerRescueTestJSON, self).setUp()
@@ -77,22 +67,12 @@
def tearDown(self):
super(ServerRescueTestJSON, self).tearDown()
- def _detach(self, server_id, volume_id):
- self.servers_client.detach_volume(server_id, volume_id)
- self.volumes_extensions_client.wait_for_volume_status(volume_id,
- 'available')
-
def _unrescue(self, server_id):
resp, body = self.servers_client.unrescue_server(server_id)
self.assertEqual(202, resp.status)
self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
- def _unpause(self, server_id):
- resp, body = self.servers_client.unpause_server(server_id)
- self.assertEqual(202, resp.status)
- self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
-
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_rescue_unrescue_instance(self):
resp, body = self.servers_client.rescue_server(
self.server_id, adminPass=self.password)
@@ -102,76 +82,7 @@
self.assertEqual(202, resp.status)
self.servers_client.wait_for_server_status(self.server_id, 'ACTIVE')
- @attr(type=['negative', 'gate'])
- def test_rescue_paused_instance(self):
- # Rescue a paused server
- resp, body = self.servers_client.pause_server(
- self.server_id)
- self.addCleanup(self._unpause, self.server_id)
- self.assertEqual(202, resp.status)
- self.servers_client.wait_for_server_status(self.server_id, 'PAUSED')
- self.assertRaises(exceptions.Conflict,
- self.servers_client.rescue_server,
- self.server_id)
-
- @attr(type=['negative', 'gate'])
- def test_rescued_vm_reboot(self):
- self.assertRaises(exceptions.Conflict, self.servers_client.reboot,
- self.rescue_id, 'HARD')
-
- @attr(type=['negative', 'gate'])
- def test_rescue_non_existent_server(self):
- # Rescue a non-existing server
- self.assertRaises(exceptions.NotFound,
- self.servers_client.rescue_server,
- '999erra43')
-
- @attr(type=['negative', 'gate'])
- def test_rescued_vm_rebuild(self):
- self.assertRaises(exceptions.Conflict,
- self.servers_client.rebuild,
- self.rescue_id,
- self.image_ref_alt)
-
- @attr(type=['negative', 'gate'])
- def test_rescued_vm_attach_volume(self):
- # Rescue the server
- self.servers_client.rescue_server(self.server_id,
- adminPass=self.password)
- self.servers_client.wait_for_server_status(self.server_id, 'RESCUE')
- self.addCleanup(self._unrescue, self.server_id)
-
- # Attach the volume to the server
- self.assertRaises(exceptions.Conflict,
- self.servers_client.attach_volume,
- self.server_id,
- self.volume['id'],
- device='/dev/%s' % self.device)
-
- @attr(type=['negative', 'gate'])
- def test_rescued_vm_detach_volume(self):
- # Attach the volume to the server
- self.servers_client.attach_volume(self.server_id,
- self.volume['id'],
- device='/dev/%s' % self.device)
- self.volumes_extensions_client.wait_for_volume_status(
- self.volume['id'], 'in-use')
-
- # Rescue the server
- self.servers_client.rescue_server(self.server_id,
- adminPass=self.password)
- self.servers_client.wait_for_server_status(self.server_id, 'RESCUE')
- # addCleanup is a LIFO queue
- self.addCleanup(self._detach, self.server_id, self.volume['id'])
- self.addCleanup(self._unrescue, self.server_id)
-
- # Detach the volume from the server expecting failure
- self.assertRaises(exceptions.Conflict,
- self.servers_client.detach_volume,
- self.server_id,
- self.volume['id'])
-
- @attr(type='gate')
+ @test.attr(type='gate')
def test_rescued_vm_associate_dissociate_floating_ip(self):
# Rescue the server
self.servers_client.rescue_server(
@@ -191,7 +102,7 @@
self.server_id)
self.assertEqual(202, resp.status)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_rescued_vm_add_remove_security_group(self):
# Rescue the server
self.servers_client.rescue_server(
diff --git a/tempest/api/compute/servers/test_server_rescue_negative.py b/tempest/api/compute/servers/test_server_rescue_negative.py
new file mode 100644
index 0000000..ffd79fa
--- /dev/null
+++ b/tempest/api/compute/servers/test_server_rescue_negative.py
@@ -0,0 +1,135 @@
+# Copyright 2013 Hewlett-Packard Development Company, L.P.
+# Copyright 2014 NEC Corporation. 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 tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest import test
+
+
+class ServerRescueNegativeTestJSON(base.BaseV2ComputeTest):
+ _interface = 'json'
+
+ @classmethod
+ def setUpClass(cls):
+ cls.set_network_resources(network=True, subnet=True, router=True)
+ super(ServerRescueNegativeTestJSON, cls).setUpClass()
+ cls.device = 'vdf'
+
+ # Create a volume and wait for it to become ready for attach
+ resp, cls.volume = cls.volumes_extensions_client.create_volume(
+ 1, display_name=data_utils.rand_name(cls.__name__ + '_volume'))
+ cls.volumes_extensions_client.wait_for_volume_status(
+ cls.volume['id'], 'available')
+
+ # Server for negative tests
+ resp, server = cls.create_test_server(wait_until='BUILD')
+ resp, resc_server = cls.create_test_server(wait_until='ACTIVE')
+ cls.server_id = server['id']
+ cls.password = server['adminPass']
+ cls.rescue_id = resc_server['id']
+ rescue_password = resc_server['adminPass']
+
+ cls.servers_client.rescue_server(
+ cls.rescue_id, adminPass=rescue_password)
+ cls.servers_client.wait_for_server_status(cls.rescue_id, 'RESCUE')
+
+ def _detach(self, server_id, volume_id):
+ self.servers_client.detach_volume(server_id, volume_id)
+ self.volumes_extensions_client.wait_for_volume_status(volume_id,
+ 'available')
+
+ def _unrescue(self, server_id):
+ resp, body = self.servers_client.unrescue_server(server_id)
+ self.assertEqual(202, resp.status)
+ self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
+
+ def _unpause(self, server_id):
+ resp, body = self.servers_client.unpause_server(server_id)
+ self.assertEqual(202, resp.status)
+ self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
+
+ @test.attr(type=['negative', 'gate'])
+ def test_rescue_paused_instance(self):
+ # Rescue a paused server
+ resp, body = self.servers_client.pause_server(self.server_id)
+ self.addCleanup(self._unpause, self.server_id)
+ self.assertEqual(202, resp.status)
+ self.servers_client.wait_for_server_status(self.server_id, 'PAUSED')
+ self.assertRaises(exceptions.Conflict,
+ self.servers_client.rescue_server,
+ self.server_id)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_rescued_vm_reboot(self):
+ self.assertRaises(exceptions.Conflict, self.servers_client.reboot,
+ self.rescue_id, 'HARD')
+
+ @test.attr(type=['negative', 'gate'])
+ def test_rescue_non_existent_server(self):
+ # Rescue a non-existing server
+ non_existent_server = data_utils.rand_uuid()
+ self.assertRaises(exceptions.NotFound,
+ self.servers_client.rescue_server,
+ non_existent_server)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_rescued_vm_rebuild(self):
+ self.assertRaises(exceptions.Conflict,
+ self.servers_client.rebuild,
+ self.rescue_id,
+ self.image_ref_alt)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_rescued_vm_attach_volume(self):
+ # Rescue the server
+ self.servers_client.rescue_server(self.server_id,
+ adminPass=self.password)
+ self.servers_client.wait_for_server_status(self.server_id, 'RESCUE')
+ self.addCleanup(self._unrescue, self.server_id)
+
+ # Attach the volume to the server
+ self.assertRaises(exceptions.Conflict,
+ self.servers_client.attach_volume,
+ self.server_id,
+ self.volume['id'],
+ device='/dev/%s' % self.device)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_rescued_vm_detach_volume(self):
+ # Attach the volume to the server
+ self.servers_client.attach_volume(self.server_id,
+ self.volume['id'],
+ device='/dev/%s' % self.device)
+ self.volumes_extensions_client.wait_for_volume_status(
+ self.volume['id'], 'in-use')
+
+ # Rescue the server
+ self.servers_client.rescue_server(self.server_id,
+ adminPass=self.password)
+ self.servers_client.wait_for_server_status(self.server_id, 'RESCUE')
+ # addCleanup is a LIFO queue
+ self.addCleanup(self._detach, self.server_id, self.volume['id'])
+ self.addCleanup(self._unrescue, self.server_id)
+
+ # Detach the volume from the server expecting failure
+ self.assertRaises(exceptions.Conflict,
+ self.servers_client.detach_volume,
+ self.server_id,
+ self.volume['id'])
+
+
+class ServerRescueNegativeTestXML(ServerRescueNegativeTestJSON):
+ _interface = 'xml'
diff --git a/tempest/api/compute/test_live_block_migration_negative.py b/tempest/api/compute/test_live_block_migration_negative.py
index da0e4c4..e1a264e 100644
--- a/tempest/api/compute/test_live_block_migration_negative.py
+++ b/tempest/api/compute/test_live_block_migration_negative.py
@@ -38,7 +38,7 @@
def _migrate_server_to(self, server_id, dest_host):
_resp, body = self.admin_servers_client.live_migrate_server(
server_id, dest_host,
- self.config.compute_feature_enabled.
+ CONF.compute_feature_enabled.
block_migration_for_live_migration)
return body
diff --git a/tempest/api/compute/v3/admin/test_aggregates.py b/tempest/api/compute/v3/admin/test_aggregates.py
index 20093e4..e5ec08b 100644
--- a/tempest/api/compute/v3/admin/test_aggregates.py
+++ b/tempest/api/compute/v3/admin/test_aggregates.py
@@ -26,7 +26,6 @@
"""
_host_key = 'os-extended-server-attributes:host'
- _interface = 'json'
@classmethod
def setUpClass(cls):
@@ -47,7 +46,7 @@
resp, aggregate = self.client.create_aggregate(name=aggregate_name)
self.assertEqual(201, resp.status)
self.assertEqual(aggregate_name, aggregate['name'])
- self.assertEqual(None, aggregate['availability_zone'])
+ self.assertIsNone(aggregate['availability_zone'])
resp, _ = self.client.delete_aggregate(aggregate['id'])
self.assertEqual(204, resp.status)
@@ -176,7 +175,7 @@
self.assertEqual(1, len(aggs))
agg = aggs[0]
self.assertEqual(aggregate_name, agg['name'])
- self.assertEqual(None, agg['availability_zone'])
+ self.assertIsNone(agg['availability_zone'])
self.assertIn(self.host, agg['hosts'])
@test.attr(type='gate')
@@ -191,7 +190,7 @@
resp, body = self.client.get_aggregate(aggregate['id'])
self.assertEqual(aggregate_name, body['name'])
- self.assertEqual(None, body['availability_zone'])
+ self.assertIsNone(body['availability_zone'])
self.assertIn(self.host, body['hosts'])
@test.attr(type='gate')
diff --git a/tempest/api/compute/v3/admin/test_aggregates_negative.py b/tempest/api/compute/v3/admin/test_aggregates_negative.py
index 5700460..1505f74 100644
--- a/tempest/api/compute/v3/admin/test_aggregates_negative.py
+++ b/tempest/api/compute/v3/admin/test_aggregates_negative.py
@@ -26,8 +26,6 @@
Tests Aggregates API that require admin privileges
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(AggregatesAdminNegativeV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_availability_zone.py b/tempest/api/compute/v3/admin/test_availability_zone.py
index 176751f..9ca8953 100644
--- a/tempest/api/compute/v3/admin/test_availability_zone.py
+++ b/tempest/api/compute/v3/admin/test_availability_zone.py
@@ -23,8 +23,6 @@
Tests Availability Zone API List
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(AZAdminV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_availability_zone_negative.py b/tempest/api/compute/v3/admin/test_availability_zone_negative.py
index 180f298..f3af6df 100644
--- a/tempest/api/compute/v3/admin/test_availability_zone_negative.py
+++ b/tempest/api/compute/v3/admin/test_availability_zone_negative.py
@@ -24,8 +24,6 @@
Tests Availability Zone API List
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(AZAdminNegativeV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_flavors.py b/tempest/api/compute/v3/admin/test_flavors.py
index 597c99b..401eb85 100644
--- a/tempest/api/compute/v3/admin/test_flavors.py
+++ b/tempest/api/compute/v3/admin/test_flavors.py
@@ -27,8 +27,6 @@
Tests Flavors API Create and Delete that require admin privileges
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(FlavorsAdminV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_flavors_access.py b/tempest/api/compute/v3/admin/test_flavors_access.py
index 43dc726..03305ff 100644
--- a/tempest/api/compute/v3/admin/test_flavors_access.py
+++ b/tempest/api/compute/v3/admin/test_flavors_access.py
@@ -25,8 +25,6 @@
Add and remove Flavor Access require admin privileges.
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(FlavorsAccessV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_flavors_access_negative.py b/tempest/api/compute/v3/admin/test_flavors_access_negative.py
index 6a2e826..334d124 100644
--- a/tempest/api/compute/v3/admin/test_flavors_access_negative.py
+++ b/tempest/api/compute/v3/admin/test_flavors_access_negative.py
@@ -28,8 +28,6 @@
Add and remove Flavor Access require admin privileges.
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(FlavorsAccessNegativeV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_flavors_extra_specs.py b/tempest/api/compute/v3/admin/test_flavors_extra_specs.py
index 4d22027..29cd8db 100644
--- a/tempest/api/compute/v3/admin/test_flavors_extra_specs.py
+++ b/tempest/api/compute/v3/admin/test_flavors_extra_specs.py
@@ -26,8 +26,6 @@
GET Flavor Extra specs can be performed even by without admin privileges.
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(FlavorsExtraSpecsV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_flavors_extra_specs_negative.py b/tempest/api/compute/v3/admin/test_flavors_extra_specs_negative.py
index 98e6e3d..e9c04a3 100644
--- a/tempest/api/compute/v3/admin/test_flavors_extra_specs_negative.py
+++ b/tempest/api/compute/v3/admin/test_flavors_extra_specs_negative.py
@@ -27,8 +27,6 @@
SET, UNSET, UPDATE Flavor Extra specs require admin privileges.
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(FlavorsExtraSpecsNegativeV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_flavors_negative.py b/tempest/api/compute/v3/admin/test_flavors_negative.py
index f54de79..3f8a2da 100644
--- a/tempest/api/compute/v3/admin/test_flavors_negative.py
+++ b/tempest/api/compute/v3/admin/test_flavors_negative.py
@@ -27,8 +27,6 @@
Tests Flavors API Create and Delete that require admin privileges
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(FlavorsAdminNegativeV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_hosts.py b/tempest/api/compute/v3/admin/test_hosts.py
index 2c9369f..8cb1f23 100644
--- a/tempest/api/compute/v3/admin/test_hosts.py
+++ b/tempest/api/compute/v3/admin/test_hosts.py
@@ -23,8 +23,6 @@
Tests hosts API using admin privileges.
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(HostsAdminV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_hosts_negative.py b/tempest/api/compute/v3/admin/test_hosts_negative.py
index ac5d7de..79cd97f 100644
--- a/tempest/api/compute/v3/admin/test_hosts_negative.py
+++ b/tempest/api/compute/v3/admin/test_hosts_negative.py
@@ -24,8 +24,6 @@
Tests hosts API using admin privileges.
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(HostsAdminNegativeV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_hypervisor.py b/tempest/api/compute/v3/admin/test_hypervisor.py
index 0f96bba..93d4441 100644
--- a/tempest/api/compute/v3/admin/test_hypervisor.py
+++ b/tempest/api/compute/v3/admin/test_hypervisor.py
@@ -23,8 +23,6 @@
Tests Hypervisors API that require admin privileges
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(HypervisorAdminV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_hypervisor_negative.py b/tempest/api/compute/v3/admin/test_hypervisor_negative.py
index aee354a..45642b7 100644
--- a/tempest/api/compute/v3/admin/test_hypervisor_negative.py
+++ b/tempest/api/compute/v3/admin/test_hypervisor_negative.py
@@ -27,8 +27,6 @@
Tests Hypervisors API that require admin privileges
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(HypervisorAdminNegativeV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_quotas.py b/tempest/api/compute/v3/admin/test_quotas.py
index b388b70..0c138bb 100644
--- a/tempest/api/compute/v3/admin/test_quotas.py
+++ b/tempest/api/compute/v3/admin/test_quotas.py
@@ -22,7 +22,6 @@
class QuotasAdminV3Test(base.BaseV3ComputeAdminTest):
- _interface = 'json'
force_tenant_isolation = True
@classmethod
diff --git a/tempest/api/compute/v3/admin/test_servers.py b/tempest/api/compute/v3/admin/test_servers.py
index 0dc3dbc..7787770 100644
--- a/tempest/api/compute/v3/admin/test_servers.py
+++ b/tempest/api/compute/v3/admin/test_servers.py
@@ -25,7 +25,6 @@
"""
_host_key = 'os-extended-server-attributes:host'
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/v3/admin/test_servers_negative.py b/tempest/api/compute/v3/admin/test_servers_negative.py
index a6a5736..cc1be4e 100644
--- a/tempest/api/compute/v3/admin/test_servers_negative.py
+++ b/tempest/api/compute/v3/admin/test_servers_negative.py
@@ -26,8 +26,6 @@
Tests Servers API using admin privileges
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(ServersAdminNegativeV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_services.py b/tempest/api/compute/v3/admin/test_services.py
index 8d6e549..914a2a4 100644
--- a/tempest/api/compute/v3/admin/test_services.py
+++ b/tempest/api/compute/v3/admin/test_services.py
@@ -24,8 +24,6 @@
Tests Services API. List and Enable/Disable require admin privileges.
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(ServicesAdminV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_services_negative.py b/tempest/api/compute/v3/admin/test_services_negative.py
index c270842..3168af2 100644
--- a/tempest/api/compute/v3/admin/test_services_negative.py
+++ b/tempest/api/compute/v3/admin/test_services_negative.py
@@ -25,8 +25,6 @@
Tests Services API. List and Enable/Disable require admin privileges.
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(ServicesAdminNegativeV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/certificates/test_certificates.py b/tempest/api/compute/v3/certificates/test_certificates.py
index 5c980c0..ce025fc 100644
--- a/tempest/api/compute/v3/certificates/test_certificates.py
+++ b/tempest/api/compute/v3/certificates/test_certificates.py
@@ -18,7 +18,6 @@
class CertificatesV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@attr(type='gate')
def test_create_and_get_root_certificate(self):
diff --git a/tempest/api/compute/v3/flavors/test_flavors.py b/tempest/api/compute/v3/flavors/test_flavors.py
index 812358f..a0bbba6 100644
--- a/tempest/api/compute/v3/flavors/test_flavors.py
+++ b/tempest/api/compute/v3/flavors/test_flavors.py
@@ -18,7 +18,6 @@
class FlavorsV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/v3/flavors/test_flavors_negative.py b/tempest/api/compute/v3/flavors/test_flavors_negative.py
index 3d4100a..346f6d6 100644
--- a/tempest/api/compute/v3/flavors/test_flavors_negative.py
+++ b/tempest/api/compute/v3/flavors/test_flavors_negative.py
@@ -24,7 +24,6 @@
class FlavorsListNegativeV3Test(base.BaseV3ComputeTest,
test.NegativeAutoTest):
- _interface = 'json'
_service = 'computev3'
_schema_file = 'compute/flavors/flavors_list_v3.json'
@@ -37,7 +36,6 @@
class FlavorDetailsNegativeV3Test(base.BaseV3ComputeTest,
test.NegativeAutoTest):
- _interface = 'json'
_service = 'computev3'
_schema_file = 'compute/flavors/flavor_details_v3.json'
diff --git a/tempest/api/compute/v3/images/test_images.py b/tempest/api/compute/v3/images/test_images.py
index b045630..656f7ba 100644
--- a/tempest/api/compute/v3/images/test_images.py
+++ b/tempest/api/compute/v3/images/test_images.py
@@ -22,7 +22,6 @@
class ImagesV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/v3/images/test_images_oneserver.py b/tempest/api/compute/v3/images/test_images_oneserver.py
index 1ded4e4..48a885e 100644
--- a/tempest/api/compute/v3/images/test_images_oneserver.py
+++ b/tempest/api/compute/v3/images/test_images_oneserver.py
@@ -26,7 +26,6 @@
class ImagesOneServerV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
def setUp(self):
# NOTE(afazekas): Normally we use the same server with all test cases,
diff --git a/tempest/api/compute/v3/images/test_images_oneserver_negative.py b/tempest/api/compute/v3/images/test_images_oneserver_negative.py
index 8d2517e..7679eee 100644
--- a/tempest/api/compute/v3/images/test_images_oneserver_negative.py
+++ b/tempest/api/compute/v3/images/test_images_oneserver_negative.py
@@ -27,7 +27,6 @@
class ImagesOneServerNegativeV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
def tearDown(self):
"""Terminate test instances created after a test is executed."""
diff --git a/tempest/api/compute/v3/keypairs/test_keypairs.py b/tempest/api/compute/v3/keypairs/test_keypairs.py
index 8eef811..668a295 100644
--- a/tempest/api/compute/v3/keypairs/test_keypairs.py
+++ b/tempest/api/compute/v3/keypairs/test_keypairs.py
@@ -19,7 +19,6 @@
class KeyPairsV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/v3/keypairs/test_keypairs_negative.py b/tempest/api/compute/v3/keypairs/test_keypairs_negative.py
index ae22ccc..e426b85 100644
--- a/tempest/api/compute/v3/keypairs/test_keypairs_negative.py
+++ b/tempest/api/compute/v3/keypairs/test_keypairs_negative.py
@@ -21,7 +21,6 @@
class KeyPairsNegativeV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/v3/servers/test_attach_interfaces.py b/tempest/api/compute/v3/servers/test_attach_interfaces.py
index 272cb53..e1c69d9 100644
--- a/tempest/api/compute/v3/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/v3/servers/test_attach_interfaces.py
@@ -24,7 +24,6 @@
class AttachInterfacesV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
@@ -48,6 +47,7 @@
def _create_server_get_interfaces(self):
resp, server = self.create_test_server(wait_until='ACTIVE')
resp, ifs = self.client.list_interfaces(server['id'])
+ self.assertEqual(200, resp.status)
resp, body = self.client.wait_for_interface_status(
server['id'], ifs[0]['port_id'], 'ACTIVE')
ifs[0]['port_state'] = body['port_state']
@@ -55,6 +55,7 @@
def _test_create_interface(self, server):
resp, iface = self.client.create_interface(server['id'])
+ self.assertEqual(200, resp.status)
resp, iface = self.client.wait_for_interface_status(
server['id'], iface['port_id'], 'ACTIVE')
self._check_interface(iface)
@@ -64,6 +65,7 @@
network_id = ifs[0]['net_id']
resp, iface = self.client.create_interface(server['id'],
network_id=network_id)
+ self.assertEqual(200, resp.status)
resp, iface = self.client.wait_for_interface_status(
server['id'], iface['port_id'], 'ACTIVE')
self._check_interface(iface, network_id=network_id)
@@ -73,12 +75,14 @@
iface = ifs[0]
resp, _iface = self.client.show_interface(server['id'],
iface['port_id'])
+ self.assertEqual(200, resp.status)
self.assertEqual(iface, _iface)
def _test_delete_interface(self, server, ifs):
# NOTE(danms): delete not the first or last, but one in the middle
iface = ifs[1]
- self.client.delete_interface(server['id'], iface['port_id'])
+ resp, _ = self.client.delete_interface(server['id'], iface['port_id'])
+ self.assertEqual(202, resp.status)
_ifs = self.client.list_interfaces(server['id'])[1]
start = int(time.time())
@@ -122,3 +126,30 @@
_ifs = self._test_delete_interface(server, ifs)
self.assertEqual(len(ifs) - 1, len(_ifs))
+
+ @attr(type='gate')
+ def test_add_remove_fixed_ip(self):
+ # Add and Remove the fixed IP to server.
+ server, ifs = self._create_server_get_interfaces()
+ interface_count = len(ifs)
+ self.assertGreater(interface_count, 0)
+ self._check_interface(ifs[0])
+ network_id = ifs[0]['net_id']
+ resp, body = self.client.add_fixed_ip(server['id'],
+ network_id)
+ self.assertEqual(202, resp.status)
+ server_resp, server_detail = self.servers_client.get_server(
+ server['id'])
+ # Get the Fixed IP from server.
+ fixed_ip = None
+ for ip_set in server_detail['addresses']:
+ for ip in server_detail['addresses'][ip_set]:
+ if ip['type'] == 'fixed':
+ fixed_ip = ip['addr']
+ break
+ if fixed_ip is not None:
+ break
+ # Remove the fixed IP from server.
+ resp, body = self.client.remove_fixed_ip(server['id'],
+ fixed_ip)
+ self.assertEqual(202, resp.status)
diff --git a/tempest/api/compute/v3/servers/test_attach_volume.py b/tempest/api/compute/v3/servers/test_attach_volume.py
index 2edf934..8577aab 100644
--- a/tempest/api/compute/v3/servers/test_attach_volume.py
+++ b/tempest/api/compute/v3/servers/test_attach_volume.py
@@ -24,7 +24,6 @@
class AttachVolumeV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
run_ssh = CONF.compute.run_ssh
def __init__(self, *args, **kwargs):
diff --git a/tempest/api/compute/v3/servers/test_create_server.py b/tempest/api/compute/v3/servers/test_create_server.py
index 0825381..a212ca5 100644
--- a/tempest/api/compute/v3/servers/test_create_server.py
+++ b/tempest/api/compute/v3/servers/test_create_server.py
@@ -28,7 +28,6 @@
class ServersV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
run_ssh = CONF.compute.run_ssh
disk_config = 'AUTO'
@@ -119,7 +118,6 @@
class ServersWithSpecificFlavorV3Test(base.BaseV3ComputeAdminTest):
- _interface = 'json'
run_ssh = CONF.compute.run_ssh
disk_config = 'AUTO'
diff --git a/tempest/api/compute/v3/servers/test_delete_server.py b/tempest/api/compute/v3/servers/test_delete_server.py
index f53ab6e..1777dce 100644
--- a/tempest/api/compute/v3/servers/test_delete_server.py
+++ b/tempest/api/compute/v3/servers/test_delete_server.py
@@ -12,6 +12,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+import testtools
+
from tempest.api.compute import base
from tempest import config
from tempest import test
@@ -35,6 +37,7 @@
resp, server = self.create_test_server(wait_until='BUILD')
resp, _ = self.client.delete_server(server['id'])
self.assertEqual('204', resp['status'])
+ self.client.wait_for_server_termination(server['id'])
@test.attr(type='gate')
def test_delete_active_server(self):
@@ -42,6 +45,7 @@
resp, server = self.create_test_server(wait_until='ACTIVE')
resp, _ = self.client.delete_server(server['id'])
self.assertEqual('204', resp['status'])
+ self.client.wait_for_server_termination(server['id'])
@test.attr(type='gate')
def test_delete_server_while_in_shutoff_state(self):
@@ -51,6 +55,7 @@
self.client.wait_for_server_status(server['id'], 'SHUTOFF')
resp, _ = self.client.delete_server(server['id'])
self.assertEqual('204', resp['status'])
+ self.client.wait_for_server_termination(server['id'])
@test.attr(type='gate')
def test_delete_server_while_in_pause_state(self):
@@ -60,6 +65,7 @@
self.client.wait_for_server_status(server['id'], 'PAUSED')
resp, _ = self.client.delete_server(server['id'])
self.assertEqual('204', resp['status'])
+ self.client.wait_for_server_termination(server['id'])
@test.attr(type='gate')
def test_delete_server_while_in_shelved_state(self):
@@ -79,6 +85,20 @@
resp, _ = self.client.delete_server(server['id'])
self.assertEqual('204', resp['status'])
+ self.client.wait_for_server_termination(server['id'])
+
+ @testtools.skipIf(not CONF.compute_feature_enabled.resize,
+ 'Resize not available.')
+ @test.attr(type='gate')
+ def test_delete_server_while_in_verify_resize_state(self):
+ # Delete a server while it's VM state is VERIFY_RESIZE
+ resp, server = self.create_test_server(wait_until='ACTIVE')
+ resp, body = self.client.resize(server['id'], self.flavor_ref_alt)
+ self.assertEqual(202, resp.status)
+ self.client.wait_for_server_status(server['id'], 'VERIFY_RESIZE')
+ resp, _ = self.client.delete_server(server['id'])
+ self.assertEqual('204', resp['status'])
+ self.client.wait_for_server_termination(server['id'])
class DeleteServersAdminV3Test(base.BaseV3ComputeAdminTest):
@@ -103,6 +123,8 @@
self.assertEqual(server['status'], 'ERROR')
resp, _ = self.non_admin_client.delete_server(server['id'])
self.assertEqual('204', resp['status'])
+ self.servers_client.wait_for_server_termination(server['id'],
+ ignore_error=True)
@test.attr(type='gate')
def test_admin_delete_servers_of_others(self):
diff --git a/tempest/api/compute/v3/servers/test_instance_actions.py b/tempest/api/compute/v3/servers/test_instance_actions.py
index c4f6e14..7d25100 100644
--- a/tempest/api/compute/v3/servers/test_instance_actions.py
+++ b/tempest/api/compute/v3/servers/test_instance_actions.py
@@ -18,14 +18,13 @@
class InstanceActionsV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
super(InstanceActionsV3Test, cls).setUpClass()
cls.client = cls.servers_client
resp, server = cls.create_test_server(wait_until='ACTIVE')
- cls.request_id = resp['x-compute-request-id']
+ cls.resp = resp
cls.server_id = server['id']
@test.attr(type='gate')
@@ -41,10 +40,12 @@
self.assertTrue(any([i for i in body if i['action'] == 'reboot']))
@test.attr(type='gate')
+ @test.skip_because(bug="1281915")
def test_get_instance_action(self):
# Get the action details of the provided server
+ request_id = self.resp['x-compute-request-id']
resp, body = self.client.get_instance_action(self.server_id,
- self.request_id)
+ request_id)
self.assertEqual(200, resp.status)
self.assertEqual(self.server_id, body['instance_uuid'])
self.assertEqual('create', body['action'])
diff --git a/tempest/api/compute/v3/servers/test_list_server_filters.py b/tempest/api/compute/v3/servers/test_list_server_filters.py
index e08125b..ec31e8e 100644
--- a/tempest/api/compute/v3/servers/test_list_server_filters.py
+++ b/tempest/api/compute/v3/servers/test_list_server_filters.py
@@ -24,7 +24,6 @@
class ListServerFiltersV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/v3/servers/test_list_servers_negative.py b/tempest/api/compute/v3/servers/test_list_servers_negative.py
index 09e1bb6..92f44fe 100644
--- a/tempest/api/compute/v3/servers/test_list_servers_negative.py
+++ b/tempest/api/compute/v3/servers/test_list_servers_negative.py
@@ -15,13 +15,14 @@
import datetime
+from six import moves
+
from tempest.api.compute import base
from tempest import exceptions
from tempest.test import attr
class ListServersNegativeV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
force_tenant_isolation = True
@classmethod
@@ -36,7 +37,7 @@
cls.existing_fixtures = []
cls.deleted_fixtures = []
cls.start_time = datetime.datetime.utcnow()
- for x in xrange(2):
+ for x in moves.xrange(2):
resp, srv = cls.create_test_server()
cls.existing_fixtures.append(srv)
diff --git a/tempest/api/compute/v3/servers/test_multiple_create.py b/tempest/api/compute/v3/servers/test_multiple_create.py
index f1ae5f8..23e0854 100644
--- a/tempest/api/compute/v3/servers/test_multiple_create.py
+++ b/tempest/api/compute/v3/servers/test_multiple_create.py
@@ -15,12 +15,10 @@
from tempest.api.compute import base
from tempest.common.utils import data_utils
-from tempest import exceptions
from tempest import test
class MultipleCreateV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
_name = 'multiple-create-test'
def _generate_name(self):
@@ -47,38 +45,6 @@
self.assertEqual('202', resp['status'])
self.assertNotIn('reservation_id', body)
- @test.attr(type=['negative', 'gate'])
- def test_min_count_less_than_one(self):
- invalid_min_count = 0
- self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
- min_count=invalid_min_count)
-
- @test.attr(type=['negative', 'gate'])
- def test_min_count_non_integer(self):
- invalid_min_count = 2.5
- self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
- min_count=invalid_min_count)
-
- @test.attr(type=['negative', 'gate'])
- def test_max_count_less_than_one(self):
- invalid_max_count = 0
- self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
- max_count=invalid_max_count)
-
- @test.attr(type=['negative', 'gate'])
- def test_max_count_non_integer(self):
- invalid_max_count = 2.5
- self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
- max_count=invalid_max_count)
-
- @test.attr(type=['negative', 'gate'])
- def test_max_count_less_than_min_count(self):
- min_count = 3
- max_count = 2
- self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
- min_count=min_count,
- max_count=max_count)
-
@test.attr(type='gate')
def test_multiple_create_with_reservation_return(self):
resp, body = self._create_multiple_servers(wait_until='ACTIVE',
diff --git a/tempest/api/compute/v3/servers/test_multiple_create_negative.py b/tempest/api/compute/v3/servers/test_multiple_create_negative.py
new file mode 100644
index 0000000..57bb807
--- /dev/null
+++ b/tempest/api/compute/v3/servers/test_multiple_create_negative.py
@@ -0,0 +1,69 @@
+# Copyright 2013 IBM Corp
+# 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 tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest import test
+
+
+class MultipleCreateV3NegativeTest(base.BaseV3ComputeTest):
+ _interface = 'json'
+ _name = 'multiple-create-negative-test'
+
+ def _generate_name(self):
+ return data_utils.rand_name(self._name)
+
+ def _create_multiple_servers(self, name=None, wait_until=None, **kwargs):
+ """
+ This is the right way to create_multiple servers and manage to get the
+ created servers into the servers list to be cleaned up after all.
+ """
+ kwargs['name'] = kwargs.get('name', self._generate_name())
+ resp, body = self.create_test_server(**kwargs)
+
+ return resp, body
+
+ @test.attr(type=['negative', 'gate'])
+ def test_min_count_less_than_one(self):
+ invalid_min_count = 0
+ self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
+ min_count=invalid_min_count)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_min_count_non_integer(self):
+ invalid_min_count = 2.5
+ self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
+ min_count=invalid_min_count)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_max_count_less_than_one(self):
+ invalid_max_count = 0
+ self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
+ max_count=invalid_max_count)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_max_count_non_integer(self):
+ invalid_max_count = 2.5
+ self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
+ max_count=invalid_max_count)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_max_count_less_than_min_count(self):
+ min_count = 3
+ max_count = 2
+ self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
+ min_count=min_count,
+ max_count=max_count)
diff --git a/tempest/api/compute/v3/servers/test_server_actions.py b/tempest/api/compute/v3/servers/test_server_actions.py
index 6584b93..406c45a 100644
--- a/tempest/api/compute/v3/servers/test_server_actions.py
+++ b/tempest/api/compute/v3/servers/test_server_actions.py
@@ -28,7 +28,6 @@
class ServerActionsV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
resize_available = CONF.compute_feature_enabled.resize
run_ssh = CONF.compute.run_ssh
@@ -411,3 +410,16 @@
resp, server = self.servers_client.start(self.server_id)
self.assertEqual(202, resp.status)
self.servers_client.wait_for_server_status(self.server_id, 'ACTIVE')
+
+ @testtools.skipUnless(CONF.compute_feature_enabled.vnc_console,
+ 'VNC Console feature is disabled')
+ @test.attr(type='gate')
+ def test_get_vnc_console(self):
+ # Get the VNC console
+ console_types = ['novnc', 'xvpvnc']
+ for console_type in console_types:
+ resp, body = self.servers_client.get_vnc_console(self.server_id,
+ console_type)
+ self.assertEqual(200, resp.status)
+ self.assertEqual(console_type, body['type'])
+ self.assertNotEqual('', body['url'])
diff --git a/tempest/api/compute/v3/servers/test_server_addresses.py b/tempest/api/compute/v3/servers/test_server_addresses.py
index 038e254..efd7500 100644
--- a/tempest/api/compute/v3/servers/test_server_addresses.py
+++ b/tempest/api/compute/v3/servers/test_server_addresses.py
@@ -15,14 +15,12 @@
from tempest.api.compute import base
from tempest import config
-from tempest import exceptions
from tempest import test
CONF = config.CONF
class ServerAddressesV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
@@ -33,19 +31,6 @@
resp, cls.server = cls.create_test_server(wait_until='ACTIVE')
- @test.attr(type=['negative', 'gate'])
- def test_list_server_addresses_invalid_server_id(self):
- # List addresses request should fail if server id not in system
- self.assertRaises(exceptions.NotFound, self.client.list_addresses,
- '999')
-
- @test.attr(type=['negative', 'gate'])
- def test_list_server_addresses_by_network_neg(self):
- # List addresses by network should fail if network name not valid
- self.assertRaises(exceptions.NotFound,
- self.client.list_addresses_by_network,
- self.server['id'], 'invalid')
-
@test.skip_because(bug="1210483",
condition=CONF.service_available.neutron)
@test.attr(type='smoke')
diff --git a/tempest/api/compute/v3/servers/test_server_addresses_negative.py b/tempest/api/compute/v3/servers/test_server_addresses_negative.py
new file mode 100644
index 0000000..8a9877b
--- /dev/null
+++ b/tempest/api/compute/v3/servers/test_server_addresses_negative.py
@@ -0,0 +1,46 @@
+# Copyright 2012 OpenStack Foundation
+# 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 tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest import test
+
+
+class ServerAddressesV3NegativeTest(base.BaseV3ComputeTest):
+ _interface = 'json'
+
+ @classmethod
+ def setUpClass(cls):
+ # This test module might use a network and a subnet
+ cls.set_network_resources(network=True, subnet=True)
+ super(ServerAddressesV3NegativeTest, cls).setUpClass()
+ cls.client = cls.servers_client
+
+ resp, cls.server = cls.create_test_server(wait_until='ACTIVE')
+
+ @test.attr(type=['negative', 'gate'])
+ def test_list_server_addresses_nonexistent_server_id(self):
+ # List addresses request should fail if server id not in system
+ non_existent_server_id = data_utils.rand_uuid()
+ self.assertRaises(exceptions.NotFound, self.client.list_addresses,
+ non_existent_server_id)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_list_server_addresses_by_network_neg(self):
+ # List addresses by network should fail if network name not valid
+ self.assertRaises(exceptions.NotFound,
+ self.client.list_addresses_by_network,
+ self.server['id'], 'invalid')
diff --git a/tempest/api/compute/v3/servers/test_server_metadata.py b/tempest/api/compute/v3/servers/test_server_metadata.py
index 13c82dd..0e4ef07 100644
--- a/tempest/api/compute/v3/servers/test_server_metadata.py
+++ b/tempest/api/compute/v3/servers/test_server_metadata.py
@@ -18,7 +18,6 @@
class ServerMetadataV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/v3/servers/test_server_metadata_negative.py b/tempest/api/compute/v3/servers/test_server_metadata_negative.py
index ce6c340..ec2bc8c 100644
--- a/tempest/api/compute/v3/servers/test_server_metadata_negative.py
+++ b/tempest/api/compute/v3/servers/test_server_metadata_negative.py
@@ -19,7 +19,6 @@
class ServerMetadataV3NegativeTest(base.BaseV3ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/v3/servers/test_server_password.py b/tempest/api/compute/v3/servers/test_server_password.py
index 579a8a5..fc0b145 100644
--- a/tempest/api/compute/v3/servers/test_server_password.py
+++ b/tempest/api/compute/v3/servers/test_server_password.py
@@ -19,7 +19,6 @@
class ServerPasswordV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/v3/servers/test_server_rescue.py b/tempest/api/compute/v3/servers/test_server_rescue.py
index fa7def0..5d7f91d 100644
--- a/tempest/api/compute/v3/servers/test_server_rescue.py
+++ b/tempest/api/compute/v3/servers/test_server_rescue.py
@@ -20,7 +20,6 @@
class ServerRescueV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/v3/servers/test_servers.py b/tempest/api/compute/v3/servers/test_servers.py
index 5480e31..426ee8d 100644
--- a/tempest/api/compute/v3/servers/test_servers.py
+++ b/tempest/api/compute/v3/servers/test_servers.py
@@ -19,7 +19,6 @@
class ServersV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/v3/servers/test_servers_negative.py b/tempest/api/compute/v3/servers/test_servers_negative.py
index 12e0ad8..cb5e93d 100644
--- a/tempest/api/compute/v3/servers/test_servers_negative.py
+++ b/tempest/api/compute/v3/servers/test_servers_negative.py
@@ -27,7 +27,6 @@
class ServersNegativeV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
def setUp(self):
super(ServersNegativeV3Test, self).setUp()
diff --git a/tempest/api/compute/v3/test_extensions.py b/tempest/api/compute/v3/test_extensions.py
index 09f5ab4..3c612df 100644
--- a/tempest/api/compute/v3/test_extensions.py
+++ b/tempest/api/compute/v3/test_extensions.py
@@ -25,7 +25,6 @@
class ExtensionsV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@test.attr(type='gate')
def test_list_extensions(self):
diff --git a/tempest/api/compute/v3/test_live_block_migration.py b/tempest/api/compute/v3/test_live_block_migration.py
index 43b4e2b..33d2bd9 100644
--- a/tempest/api/compute/v3/test_live_block_migration.py
+++ b/tempest/api/compute/v3/test_live_block_migration.py
@@ -24,7 +24,6 @@
class LiveBlockMigrationV3Test(base.BaseV3ComputeAdminTest):
_host_key = 'os-extended-server-attributes:host'
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/v3/test_live_block_migration_negative.py b/tempest/api/compute/v3/test_live_block_migration_negative.py
index 4d820d8..b4ec505 100644
--- a/tempest/api/compute/v3/test_live_block_migration_negative.py
+++ b/tempest/api/compute/v3/test_live_block_migration_negative.py
@@ -25,7 +25,6 @@
class LiveBlockMigrationV3NegativeTest(base.BaseV3ComputeAdminTest):
_host_key = 'os-extended-server-attributes:host'
- _interface = 'json'
@classmethod
def setUpClass(cls):
@@ -39,7 +38,7 @@
def _migrate_server_to(self, server_id, dest_host):
_resp, body = self.admin_servers_client.live_migrate_server(
server_id, dest_host,
- self.config.compute_feature_enabled.
+ CONF.compute_feature_enabled.
block_migration_for_live_migration)
return body
diff --git a/tempest/api/compute/v3/test_quotas.py b/tempest/api/compute/v3/test_quotas.py
index 33b90ff..b53d9be 100644
--- a/tempest/api/compute/v3/test_quotas.py
+++ b/tempest/api/compute/v3/test_quotas.py
@@ -18,7 +18,6 @@
class QuotasV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/v3/test_version.py b/tempest/api/compute/v3/test_version.py
index 9161d4d..1a74e35 100644
--- a/tempest/api/compute/v3/test_version.py
+++ b/tempest/api/compute/v3/test_version.py
@@ -19,7 +19,6 @@
class VersionV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@test.attr(type='gate')
def test_version(self):
diff --git a/tempest/api/identity/admin/test_roles.py b/tempest/api/identity/admin/test_roles.py
index aa64969..5e78cce 100644
--- a/tempest/api/identity/admin/test_roles.py
+++ b/tempest/api/identity/admin/test_roles.py
@@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+from six import moves
+
from tempest.api.identity import base
from tempest.common.utils import data_utils
from tempest.test import attr
@@ -24,7 +26,7 @@
@classmethod
def setUpClass(cls):
super(RolesTestJSON, cls).setUpClass()
- for _ in xrange(5):
+ for _ in moves.xrange(5):
role_name = data_utils.rand_name(name='role-')
resp, role = cls.client.create_role(role_name)
cls.data.roles.append(role)
diff --git a/tempest/api/identity/admin/test_services.py b/tempest/api/identity/admin/test_services.py
index cbf6b58..459c44c 100644
--- a/tempest/api/identity/admin/test_services.py
+++ b/tempest/api/identity/admin/test_services.py
@@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+from six import moves
from tempest.api.identity import base
from tempest.common.utils import data_utils
@@ -69,7 +70,7 @@
def test_list_services(self):
# Create, List, Verify and Delete Services
services = []
- for _ in xrange(3):
+ for _ in moves.xrange(3):
name = data_utils.rand_name('service-')
type = data_utils.rand_name('type--')
description = data_utils.rand_name('description-')
diff --git a/tempest/api/identity/admin/test_tenants.py b/tempest/api/identity/admin/test_tenants.py
index c7cacb4..257a6d7 100644
--- a/tempest/api/identity/admin/test_tenants.py
+++ b/tempest/api/identity/admin/test_tenants.py
@@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+from six import moves
+
from tempest.api.identity import base
from tempest.common.utils import data_utils
from tempest.test import attr
@@ -25,7 +27,7 @@
def test_tenant_list_delete(self):
# Create several tenants and delete them
tenants = []
- for _ in xrange(3):
+ for _ in moves.xrange(3):
tenant_name = data_utils.rand_name(name='tenant-new')
resp, tenant = self.client.create_tenant(tenant_name)
self.assertEqual(200, resp.status)
diff --git a/tempest/api/identity/admin/v3/test_endpoints.py b/tempest/api/identity/admin/v3/test_endpoints.py
index 78ecf93..05b704f 100644
--- a/tempest/api/identity/admin/v3/test_endpoints.py
+++ b/tempest/api/identity/admin/v3/test_endpoints.py
@@ -125,7 +125,7 @@
self.assertEqual(interface2, endpoint['interface'])
self.assertEqual(url2, endpoint['url'])
self.assertEqual(region2, endpoint['region'])
- self.assertEqual('False', str(endpoint['enabled']))
+ self.assertEqual('false', str(endpoint['enabled']).lower())
self.addCleanup(self.client.delete_endpoint, endpoint_for_update['id'])
diff --git a/tempest/api/identity/admin/v3/test_projects.py b/tempest/api/identity/admin/v3/test_projects.py
index f309897..31a0ddd 100644
--- a/tempest/api/identity/admin/v3/test_projects.py
+++ b/tempest/api/identity/admin/v3/test_projects.py
@@ -13,10 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
+from six import moves
+
from tempest.api.identity import base
from tempest.common.utils import data_utils
from tempest import exceptions
-from tempest.test import attr
+from tempest import test
class ProjectsTestJSON(base.BaseIdentityV3AdminTest):
@@ -28,10 +30,10 @@
self.assertRaises(
exceptions.NotFound, self.client.get_project, project_id)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_project_list_delete(self):
# Create several projects and delete them
- for _ in xrange(3):
+ for _ in moves.xrange(3):
resp, project = self.client.create_project(
data_utils.rand_name('project-new'))
self.addCleanup(self._delete_project, project['id'])
@@ -42,7 +44,7 @@
resp, get_project = self.client.get_project(project['id'])
self.assertIn(get_project, list_projects)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_project_create_with_description(self):
# Create project with a description
project_name = data_utils.rand_name('project-')
@@ -61,7 +63,7 @@
self.assertEqual(desc2, project_desc, 'Description does not appear'
'to be set')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_project_create_enabled(self):
# Create a project that is enabled
project_name = data_utils.rand_name('project-')
@@ -77,7 +79,7 @@
en2 = body['enabled']
self.assertTrue(en2, 'Enable should be True in lookup')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_project_create_not_enabled(self):
# Create a project that is not enabled
project_name = data_utils.rand_name('project-')
@@ -94,7 +96,7 @@
self.assertEqual('false', str(en2).lower(),
'Enable should be False in lookup')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_project_update_name(self):
# Update name attribute of a project
p_name1 = data_utils.rand_name('project-')
@@ -117,7 +119,7 @@
self.assertEqual(p_name1, resp1_name)
self.assertEqual(resp2_name, resp3_name)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_project_update_desc(self):
# Update description attribute of a project
p_name = data_utils.rand_name('project-')
@@ -142,7 +144,7 @@
self.assertEqual(p_desc, resp1_desc)
self.assertEqual(resp2_desc, resp3_desc)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_project_update_enable(self):
# Update the enabled attribute of a project
p_name = data_utils.rand_name('project-')
@@ -167,7 +169,7 @@
self.assertEqual('false', str(resp1_en).lower())
self.assertEqual(resp2_en, resp3_en)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_associate_user_to_project(self):
#Associate a user to a project
#Create a Project
@@ -196,59 +198,6 @@
new_user_get['project_id'])
self.assertEqual(u_email, new_user_get['email'])
- @attr(type=['negative', 'gate'])
- def test_list_projects_by_unauthorized_user(self):
- # Non-admin user should not be able to list projects
- self.assertRaises(exceptions.Unauthorized,
- self.non_admin_client.list_projects)
-
- @attr(type=['negative', 'gate'])
- def test_project_create_duplicate(self):
- # Project names should be unique
- project_name = data_utils.rand_name('project-dup-')
- resp, project = self.client.create_project(project_name)
- self.data.projects.append(project)
-
- self.assertRaises(
- exceptions.Conflict, self.client.create_project, project_name)
-
- @attr(type=['negative', 'gate'])
- def test_create_project_by_unauthorized_user(self):
- # Non-admin user should not be authorized to create a project
- project_name = data_utils.rand_name('project-')
- self.assertRaises(
- exceptions.Unauthorized, self.non_admin_client.create_project,
- project_name)
-
- @attr(type=['negative', 'gate'])
- def test_create_project_with_empty_name(self):
- # Project name should not be empty
- self.assertRaises(exceptions.BadRequest, self.client.create_project,
- name='')
-
- @attr(type=['negative', 'gate'])
- def test_create_projects_name_length_over_64(self):
- # Project name length should not be greater than 64 characters
- project_name = 'a' * 65
- self.assertRaises(exceptions.BadRequest, self.client.create_project,
- project_name)
-
- @attr(type=['negative', 'gate'])
- def test_project_delete_by_unauthorized_user(self):
- # Non-admin user should not be able to delete a project
- project_name = data_utils.rand_name('project-')
- resp, project = self.client.create_project(project_name)
- self.data.projects.append(project)
- self.assertRaises(
- exceptions.Unauthorized, self.non_admin_client.delete_project,
- project['id'])
-
- @attr(type=['negative', 'gate'])
- def test_delete_non_existent_project(self):
- # Attempt to delete a non existent project should fail
- self.assertRaises(exceptions.NotFound, self.client.delete_project,
- 'junk_Project_123456abc')
-
class ProjectsTestXML(ProjectsTestJSON):
_interface = 'xml'
diff --git a/tempest/api/identity/admin/v3/test_projects_negative.py b/tempest/api/identity/admin/v3/test_projects_negative.py
new file mode 100644
index 0000000..6b60d04
--- /dev/null
+++ b/tempest/api/identity/admin/v3/test_projects_negative.py
@@ -0,0 +1,80 @@
+# Copyright 2013 OpenStack, LLC
+# 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 tempest.api.identity import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest import test
+
+
+class ProjectsNegativeTestJSON(base.BaseIdentityV3AdminTest):
+ _interface = 'json'
+
+ @test.attr(type=['negative', 'gate'])
+ def test_list_projects_by_unauthorized_user(self):
+ # Non-admin user should not be able to list projects
+ self.assertRaises(exceptions.Unauthorized,
+ self.non_admin_client.list_projects)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_project_create_duplicate(self):
+ # Project names should be unique
+ project_name = data_utils.rand_name('project-dup-')
+ resp, project = self.client.create_project(project_name)
+ self.data.projects.append(project)
+
+ self.assertRaises(
+ exceptions.Conflict, self.client.create_project, project_name)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_create_project_by_unauthorized_user(self):
+ # Non-admin user should not be authorized to create a project
+ project_name = data_utils.rand_name('project-')
+ self.assertRaises(
+ exceptions.Unauthorized, self.non_admin_client.create_project,
+ project_name)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_create_project_with_empty_name(self):
+ # Project name should not be empty
+ self.assertRaises(exceptions.BadRequest, self.client.create_project,
+ name='')
+
+ @test.attr(type=['negative', 'gate'])
+ def test_create_projects_name_length_over_64(self):
+ # Project name length should not be greater than 64 characters
+ project_name = 'a' * 65
+ self.assertRaises(exceptions.BadRequest, self.client.create_project,
+ project_name)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_project_delete_by_unauthorized_user(self):
+ # Non-admin user should not be able to delete a project
+ project_name = data_utils.rand_name('project-')
+ resp, project = self.client.create_project(project_name)
+ self.data.projects.append(project)
+ self.assertRaises(
+ exceptions.Unauthorized, self.non_admin_client.delete_project,
+ project['id'])
+
+ @test.attr(type=['negative', 'gate'])
+ def test_delete_non_existent_project(self):
+ # Attempt to delete a non existent project should fail
+ self.assertRaises(exceptions.NotFound, self.client.delete_project,
+ data_utils.rand_uuid_hex())
+
+
+class ProjectsNegativeTestXML(ProjectsNegativeTestJSON):
+ _interface = 'xml'
diff --git a/tempest/api/image/v2/test_images.py b/tempest/api/image/v2/test_images.py
index 2a5401f..d448c01 100644
--- a/tempest/api/image/v2/test_images.py
+++ b/tempest/api/image/v2/test_images.py
@@ -70,7 +70,7 @@
@attr(type='gate')
def test_delete_image(self):
- # Deletes a image by image_id
+ # Deletes an image by image_id
# Create image
image_name = data_utils.rand_name('image')
@@ -90,6 +90,43 @@
self.assertEqual(resp.status, 200)
self.assertNotIn(image_id, images)
+ @attr(type='gate')
+ def test_update_image(self):
+ # Updates an image by image_id
+
+ # Create image
+ image_name = data_utils.rand_name('image')
+ resp, body = self.client.create_image(name=image_name,
+ container_format='bare',
+ disk_format='iso',
+ visibility='public')
+ self.assertEqual(201, resp.status)
+ self.assertEqual('queued', body['status'])
+ image_id = body['id']
+
+ # Now try uploading an image file
+ file_content = '*' * 1024
+ image_file = StringIO.StringIO(file_content)
+ resp, body = self.client.store_image(image_id, image_file)
+ self.assertEqual(204, resp.status)
+
+ # Update Image
+ new_image_name = data_utils.rand_name('new-image')
+ new_visibility = 'private'
+ resp, body = self.client.update_image(image_id, [
+ dict(replace='/name', value=new_image_name),
+ dict(replace='/visibility', value=new_visibility)])
+
+ self.assertEqual(200, resp.status)
+
+ # Verifying updating
+
+ resp, body = self.client.get_image(image_id)
+ self.assertEqual(200, resp.status)
+ self.assertEqual(image_id, body['id'])
+ self.assertEqual(new_image_name, body['name'])
+ self.assertEqual(new_visibility, body['visibility'])
+
class ListImagesTest(base.BaseV2ImageTest):
"""
@@ -212,3 +249,19 @@
self.assertEqual(len(images_list), params['limit'],
"Failed to get images by limit")
+
+ @attr(type='gate')
+ def test_get_image_schema(self):
+ # Test to get image schema
+ schema = "image"
+ resp, body = self.client.get_schema(schema)
+ self.assertEqual(200, resp.status)
+ self.assertEqual("image", body['name'])
+
+ @attr(type='gate')
+ def test_get_images_schema(self):
+ # Test to get images schema
+ schema = "images"
+ resp, body = self.client.get_schema(schema)
+ self.assertEqual(200, resp.status)
+ self.assertEqual("images", body['name'])
diff --git a/tempest/api/image/v2/test_images_member.py b/tempest/api/image/v2/test_images_member.py
index 41fc49d..530262f 100644
--- a/tempest/api/image/v2/test_images_member.py
+++ b/tempest/api/image/v2/test_images_member.py
@@ -22,6 +22,7 @@
image_id = self._create_image()
resp, member = self.os_img_client.add_member(image_id,
self.alt_tenant_id)
+ self.assertEqual(200, resp.status)
self.assertEqual(member['member_id'], self.alt_tenant_id)
self.assertEqual(member['image_id'], image_id)
self.assertEqual(member['status'], 'pending')
@@ -30,7 +31,8 @@
self.alt_tenant_id,
'accepted')
self.assertIn(image_id, self._list_image_ids_as_alt())
- _, body = self.os_img_client.get_image_membership(image_id)
+ resp, body = self.os_img_client.get_image_membership(image_id)
+ self.assertEqual(200, resp.status)
members = body['members']
member = members[0]
self.assertEqual(len(members), 1, str(members))
@@ -43,11 +45,44 @@
image_id = self._create_image()
resp, member = self.os_img_client.add_member(image_id,
self.alt_tenant_id)
+ self.assertEqual(200, resp.status)
self.assertEqual(member['member_id'], self.alt_tenant_id)
self.assertEqual(member['image_id'], image_id)
self.assertEqual(member['status'], 'pending')
self.assertNotIn(image_id, self._list_image_ids_as_alt())
+ resp, _ = self.alt_img_client.update_member_status(image_id,
+ self.alt_tenant_id,
+ 'rejected')
+ self.assertEqual(200, resp.status)
+ self.assertNotIn(image_id, self._list_image_ids_as_alt())
+
+ @attr(type='gate')
+ def test_get_image_member(self):
+ image_id = self._create_image()
+ self.os_img_client.add_member(image_id,
+ self.alt_tenant_id)
self.alt_img_client.update_member_status(image_id,
self.alt_tenant_id,
- 'rejected')
+ 'accepted')
+
+ self.assertIn(image_id, self._list_image_ids_as_alt())
+ resp, member = self.os_img_client.get_member(image_id,
+ self.alt_tenant_id)
+ self.assertEqual(200, resp.status)
+ self.assertEqual(self.alt_tenant_id, member['member_id'])
+ self.assertEqual(image_id, member['image_id'])
+ self.assertEqual('accepted', member['status'])
+
+ @attr(type='gate')
+ def test_remove_image_member(self):
+ image_id = self._create_image()
+ self.os_img_client.add_member(image_id,
+ self.alt_tenant_id)
+ self.alt_img_client.update_member_status(image_id,
+ self.alt_tenant_id,
+ 'accepted')
+
+ self.assertIn(image_id, self._list_image_ids_as_alt())
+ resp = self.os_img_client.remove_member(image_id, self.alt_tenant_id)
+ self.assertEqual(204, resp.status)
self.assertNotIn(image_id, self._list_image_ids_as_alt())
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index dd888a6..8720985 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -53,8 +53,6 @@
# Default to ipv4.
_ip_version = 4
- _tenant_network_cidr = CONF.network.tenant_network_cidr
- _tenant_network_mask_bits = CONF.network.tenant_network_mask_bits
@classmethod
def setUpClass(cls):
@@ -147,8 +145,12 @@
def create_subnet(cls, network):
"""Wrapper utility that returns a test subnet."""
# The cidr and mask_bits depend on the ip version.
- cidr = netaddr.IPNetwork(cls._tenant_network_cidr)
- mask_bits = cls._tenant_network_mask_bits
+ if cls._ip_version == 4:
+ cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
+ mask_bits = CONF.network.tenant_network_mask_bits
+ elif cls._ip_version == 6:
+ cidr = netaddr.IPNetwork(CONF.network.tenant_network_v6_cidr)
+ mask_bits = CONF.network.tenant_network_v6_mask_bits
# Find a cidr that is not in use yet and create a subnet with it
body = None
failure = None
diff --git a/tempest/api/network/base_routers.py b/tempest/api/network/base_routers.py
index 304b2ca..b278002 100644
--- a/tempest/api/network/base_routers.py
+++ b/tempest/api/network/base_routers.py
@@ -38,11 +38,13 @@
self.assertNotIn(router_id, routers_list)
def _remove_router_interface_with_subnet_id(self, router_id, subnet_id):
- resp, _ = self.client.remove_router_interface_with_subnet_id(
+ resp, body = self.client.remove_router_interface_with_subnet_id(
router_id, subnet_id)
self.assertEqual('200', resp['status'])
+ self.assertEqual(subnet_id, body['subnet_id'])
def _remove_router_interface_with_port_id(self, router_id, port_id):
- resp, _ = self.client.remove_router_interface_with_port_id(
+ resp, body = self.client.remove_router_interface_with_port_id(
router_id, port_id)
self.assertEqual('200', resp['status'])
+ self.assertEqual(port_id, body['port_id'])
diff --git a/tempest/api/network/base_security_groups.py b/tempest/api/network/base_security_groups.py
index 38ae4ac..90be454 100644
--- a/tempest/api/network/base_security_groups.py
+++ b/tempest/api/network/base_security_groups.py
@@ -26,7 +26,7 @@
def _create_security_group(self):
# Create a security group
name = data_utils.rand_name('secgroup-')
- resp, group_create_body = self.client.create_security_group(name)
+ resp, group_create_body = self.client.create_security_group(name=name)
self.assertEqual('201', resp['status'])
self.addCleanup(self._delete_security_group,
group_create_body['security_group']['id'])
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index aba2c8e..654552d 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -85,8 +85,12 @@
updated_net = body['network']
self.assertEqual(updated_net['name'], new_name)
# Find a cidr that is not in use yet and create a subnet with it
- cidr = netaddr.IPNetwork(self._tenant_network_cidr)
- mask_bits = self._tenant_network_mask_bits
+ if self._ip_version == 4:
+ cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
+ mask_bits = CONF.network.tenant_network_mask_bits
+ elif self._ip_version == 6:
+ cidr = netaddr.IPNetwork(CONF.network.tenant_network_v6_cidr)
+ mask_bits = CONF.network.tenant_network_v6_mask_bits
for subnet_cidr in cidr.subnet(mask_bits):
try:
resp, body = self.client.create_subnet(
@@ -464,8 +468,6 @@
class NetworksIpV6TestJSON(NetworksTestJSON):
_ip_version = 6
- _tenant_network_cidr = CONF.network.tenant_network_v6_cidr
- _tenant_network_mask_bits = CONF.network.tenant_network_v6_mask_bits
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index d552c70..2657031 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -16,6 +16,7 @@
import netaddr
from tempest.api.network import base_routers as base
+from tempest import clients
from tempest.common.utils import data_utils
from tempest import config
from tempest import test
@@ -32,6 +33,8 @@
if not test.is_extension_enabled('router', 'network'):
msg = "router extension not enabled."
raise cls.skipException(msg)
+ admin_manager = clients.AdminManager()
+ cls.identity_admin_client = admin_manager.identity_client
@test.attr(type='smoke')
def test_create_show_list_update_delete_router(self):
@@ -77,6 +80,25 @@
self.assertEqual(show_body['router']['name'], updated_name)
@test.attr(type='smoke')
+ def test_create_router_setting_tenant_id(self):
+ # Test creating router from admin user setting tenant_id.
+ test_tenant = data_utils.rand_name('test_tenant_')
+ test_description = data_utils.rand_name('desc_')
+ _, tenant = self.identity_admin_client.create_tenant(
+ name=test_tenant,
+ description=test_description)
+ tenant_id = tenant['id']
+ self.addCleanup(self.identity_admin_client.delete_tenant, tenant_id)
+
+ name = data_utils.rand_name('router-')
+ resp, create_body = self.admin_client.create_router(
+ name, tenant_id=tenant_id)
+ self.assertEqual('201', resp['status'])
+ self.addCleanup(self.admin_client.delete_router,
+ create_body['router']['id'])
+ self.assertEqual(tenant_id, create_body['router']['tenant_id'])
+
+ @test.attr(type='smoke')
def test_add_remove_router_interface_with_subnet_id(self):
network = self.create_network()
subnet = self.create_subnet(network)
@@ -234,3 +256,48 @@
def _delete_extra_routes(self, router_id):
resp, _ = self.client.delete_extra_routes(router_id)
+
+ @test.attr(type='smoke')
+ def test_update_router_admin_state(self):
+ self.router = self.create_router(data_utils.rand_name('router-'))
+ self.assertFalse(self.router['admin_state_up'])
+ # Update router admin state
+ resp, update_body = self.client.update_router(self.router['id'],
+ admin_state_up=True)
+ self.assertEqual('200', resp['status'])
+ self.assertTrue(update_body['router']['admin_state_up'])
+ resp, show_body = self.client.show_router(self.router['id'])
+ self.assertEqual('200', resp['status'])
+ self.assertTrue(show_body['router']['admin_state_up'])
+
+ @test.attr(type='smoke')
+ def test_add_multiple_router_interfaces(self):
+ network = self.create_network()
+ subnet01 = self.create_subnet(network)
+ subnet02 = self.create_subnet(network)
+ router = self.create_router(data_utils.rand_name('router-'))
+ interface01 = self._add_router_interface_with_subnet_id(router['id'],
+ subnet01['id'])
+ self._verify_router_interface(router['id'], subnet01['id'],
+ interface01['port_id'])
+ interface02 = self._add_router_interface_with_subnet_id(router['id'],
+ subnet02['id'])
+ self._verify_router_interface(router['id'], subnet02['id'],
+ interface02['port_id'])
+
+ def _add_router_interface_with_subnet_id(self, router_id, subnet_id):
+ resp, interface = self.client.add_router_interface_with_subnet_id(
+ router_id, subnet_id)
+ self.assertEqual('200', resp['status'])
+ self.addCleanup(self._remove_router_interface_with_subnet_id,
+ router_id, subnet_id)
+ self.assertEqual(subnet_id, interface['subnet_id'])
+ return interface
+
+ def _verify_router_interface(self, router_id, subnet_id, port_id):
+ resp, show_port_body = self.client.show_port(port_id)
+ self.assertEqual('200', resp['status'])
+ interface_port = show_port_body['port']
+ self.assertEqual(router_id, interface_port['device_id'])
+ self.assertEqual(subnet_id,
+ interface_port['fixed_ips'][0]['subnet_id'])
diff --git a/tempest/api/network/test_security_groups.py b/tempest/api/network/test_security_groups.py
index 6eebf5b..1d41cc9 100644
--- a/tempest/api/network/test_security_groups.py
+++ b/tempest/api/network/test_security_groups.py
@@ -66,8 +66,9 @@
protocols = ['tcp', 'udp', 'icmp']
for protocol in protocols:
resp, rule_create_body = self.client.create_security_group_rule(
- group_create_body['security_group']['id'],
- protocol=protocol
+ security_group_id=group_create_body['security_group']['id'],
+ protocol=protocol,
+ direction='ingress'
)
self.assertEqual('201', resp['status'])
self.addCleanup(self._delete_security_group_rule,
@@ -99,7 +100,7 @@
port_range_min = 77
port_range_max = 77
resp, rule_create_body = self.client.create_security_group_rule(
- group_create_body['security_group']['id'],
+ security_group_id=group_create_body['security_group']['id'],
direction=direction,
protocol=protocol,
port_range_min=port_range_min,
diff --git a/tempest/api/network/test_security_groups_negative.py b/tempest/api/network/test_security_groups_negative.py
index e1f4055..0b86398 100644
--- a/tempest/api/network/test_security_groups_negative.py
+++ b/tempest/api/network/test_security_groups_negative.py
@@ -57,10 +57,10 @@
#Create rule with bad protocol name
pname = 'bad_protocol_name'
- self.assertRaises(exceptions.BadRequest,
- self.client.create_security_group_rule,
- group_create_body['security_group']['id'],
- protocol=pname)
+ self.assertRaises(
+ exceptions.BadRequest, self.client.create_security_group_rule,
+ security_group_id=group_create_body['security_group']['id'],
+ protocol=pname, direction='ingress')
@test.attr(type=['negative', 'gate'])
def test_create_security_group_rule_with_invalid_ports(self):
@@ -72,12 +72,11 @@
(80, 65536, 'Invalid value for port 65536'),
(-16, 65536, 'Invalid value for port')]
for pmin, pmax, msg in states:
- ex = self.assertRaises(exceptions.BadRequest,
- self.client.create_security_group_rule,
- group_create_body['security_group']['id'],
- protocol='tcp',
- port_range_min=pmin,
- port_range_max=pmax)
+ ex = self.assertRaises(
+ exceptions.BadRequest, self.client.create_security_group_rule,
+ security_group_id=group_create_body['security_group']['id'],
+ protocol='tcp', port_range_min=pmin, port_range_max=pmax,
+ direction='ingress')
self.assertIn(msg, str(ex))
@test.attr(type=['negative', 'smoke'])
@@ -86,7 +85,7 @@
name = 'default'
self.assertRaises(exceptions.Conflict,
self.client.create_security_group,
- name)
+ name=name)
@test.attr(type=['negative', 'smoke'])
def test_create_security_group_rule_with_non_existent_security_group(self):
@@ -94,7 +93,8 @@
non_existent_sg = str(uuid.uuid4())
self.assertRaises(exceptions.NotFound,
self.client.create_security_group_rule,
- non_existent_sg)
+ security_group_id=non_existent_sg,
+ direction='ingress')
class NegativeSecGroupTestXML(NegativeSecGroupTest):
diff --git a/tempest/api/object_storage/test_account_quotas.py b/tempest/api/object_storage/test_account_quotas.py
index 788292d..b14adc0 100644
--- a/tempest/api/object_storage/test_account_quotas.py
+++ b/tempest/api/object_storage/test_account_quotas.py
@@ -17,9 +17,12 @@
from tempest.api.object_storage import base
from tempest import clients
from tempest.common.utils import data_utils
+from tempest import config
from tempest import exceptions
from tempest import test
+CONF = config.CONF
+
class AccountQuotasTest(base.BaseObjectTest):
@@ -41,7 +44,7 @@
try:
_, roles = cls.os_admin.identity_client.list_roles()
reseller_role_id = next(r['id'] for r in roles if r['name']
- == 'ResellerAdmin')
+ == CONF.object_storage.reseller_admin_role)
except StopIteration:
msg = "No ResellerAdmin role found"
raise exceptions.NotFound(msg)
diff --git a/tempest/api/object_storage/test_account_quotas_negative.py b/tempest/api/object_storage/test_account_quotas_negative.py
index cab307d..402cd90 100644
--- a/tempest/api/object_storage/test_account_quotas_negative.py
+++ b/tempest/api/object_storage/test_account_quotas_negative.py
@@ -17,9 +17,12 @@
from tempest.api.object_storage import base
from tempest import clients
from tempest.common.utils import data_utils
+from tempest import config
from tempest import exceptions
from tempest import test
+CONF = config.CONF
+
class AccountQuotasNegativeTest(base.BaseObjectTest):
@@ -41,7 +44,7 @@
try:
_, roles = cls.os_admin.identity_client.list_roles()
reseller_role_id = next(r['id'] for r in roles if r['name']
- == 'ResellerAdmin')
+ == CONF.object_storage.reseller_admin_role)
except StopIteration:
msg = "No ResellerAdmin role found"
raise exceptions.NotFound(msg)
diff --git a/tempest/api/object_storage/test_account_services.py b/tempest/api/object_storage/test_account_services.py
index 5456768..7542ea1 100644
--- a/tempest/api/object_storage/test_account_services.py
+++ b/tempest/api/object_storage/test_account_services.py
@@ -15,6 +15,8 @@
import random
+from six import moves
+
from tempest.api.object_storage import base
from tempest.common import custom_matchers
from tempest.common.utils import data_utils
@@ -26,7 +28,7 @@
def setUpClass(cls):
super(AccountTest, cls).setUpClass()
cls.containers = []
- for i in xrange(ord('a'), ord('f') + 1):
+ for i in moves.xrange(ord('a'), ord('f') + 1):
name = data_utils.rand_name(name='%s-' % chr(i))
cls.container_client.create_container(name)
cls.containers.append(name)
diff --git a/tempest/api/object_storage/test_object_services.py b/tempest/api/object_storage/test_object_services.py
index 33f3299..91df292 100644
--- a/tempest/api/object_storage/test_object_services.py
+++ b/tempest/api/object_storage/test_object_services.py
@@ -14,6 +14,7 @@
# under the License.
import hashlib
+from six import moves
from tempest.api.object_storage import base
from tempest.common import custom_matchers
@@ -242,9 +243,9 @@
object_name = data_utils.rand_name(name='LObject')
data = data_utils.arbitrary_string()
segments = 10
- data_segments = [data + str(i) for i in xrange(segments)]
+ data_segments = [data + str(i) for i in moves.xrange(segments)]
# uploading segments
- for i in xrange(segments):
+ for i in moves.xrange(segments):
resp, _ = self.object_client.create_object_segments(
self.container_name, object_name, i, data_segments[i])
self.assertEqual(resp['status'], '201')
diff --git a/tempest/api/orchestration/stacks/test_neutron_resources.py b/tempest/api/orchestration/stacks/test_neutron_resources.py
index 3e621f4..291f0d1 100644
--- a/tempest/api/orchestration/stacks/test_neutron_resources.py
+++ b/tempest/api/orchestration/stacks/test_neutron_resources.py
@@ -135,7 +135,7 @@
# the cause of the server not signalling the waitcondition
# to heat.
resp, body = cls.client.get_resource(cls.stack_identifier,
- 'SmokeServerNeutron')
+ 'Server')
server_id = body['physical_resource_id']
LOG.debug('Console output for %s', server_id)
resp, output = cls.servers_client.get_console_output(
diff --git a/tempest/api/orchestration/stacks/test_swift_resources.py b/tempest/api/orchestration/stacks/test_swift_resources.py
new file mode 100644
index 0000000..5921a7a
--- /dev/null
+++ b/tempest/api/orchestration/stacks/test_swift_resources.py
@@ -0,0 +1,125 @@
+# -*- coding: utf-8 -*-
+# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
+#
+# Author: Chmouel Boudjnah <chmouel@enovance.com>
+#
+# 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.api.orchestration import base
+from tempest import clients
+from tempest.common.utils import data_utils
+from tempest import config
+
+
+CONF = config.CONF
+
+
+class SwiftResourcesTestJSON(base.BaseOrchestrationTest):
+ _interface = 'json'
+ template = """
+heat_template_version: 2013-05-23
+description: Template which creates a Swift container ressource
+
+resources:
+ SwiftContainerWebsite:
+ DeletionPolicy: "Delete"
+ Type: OS::Swift::Container
+ Properties:
+ X-Container-Read: ".r:*"
+ X-Container-Meta:
+ web-index: "index.html"
+ web-error: "error.html"
+
+ SwiftContainer:
+ Type: OS::Swift::Container
+
+outputs:
+ WebsiteURL:
+ description: "URL for website hosted on S3"
+ value: { get_attr: [SwiftContainer, WebsiteURL] }
+ DomainName:
+ description: "Domain of Swift host"
+ value: { get_attr: [SwiftContainer, DomainName] }
+
+"""
+
+ @classmethod
+ def setUpClass(cls):
+ super(SwiftResourcesTestJSON, cls).setUpClass()
+ cls.client = cls.orchestration_client
+ cls.stack_name = data_utils.rand_name('heat')
+ os = clients.Manager()
+ if not CONF.service_available.swift:
+ raise cls.skipException("Swift support is required")
+ cls.account_client = os.account_client
+ cls.container_client = os.container_client
+ # create the stack
+ cls.stack_identifier = cls.create_stack(
+ cls.stack_name,
+ cls.template)
+ cls.stack_id = cls.stack_identifier.split('/')[1]
+ cls.client.wait_for_stack_status(cls.stack_id, 'CREATE_COMPLETE')
+ cls.test_resources = {}
+ _, resources = cls.client.list_resources(cls.stack_identifier)
+ for resource in resources:
+ cls.test_resources[resource['logical_resource_id']] = resource
+
+ def test_created_resources(self):
+ """Created stack should be on the list of existing stacks."""
+ resources = [('SwiftContainer', 'OS::Swift::Container'),
+ ('SwiftContainerWebsite', 'OS::Swift::Container')]
+ for resource_name, resource_type in resources:
+ resource = self.test_resources.get(resource_name)
+ self.assertIsInstance(resource, dict)
+ self.assertEqual(resource_type, resource['resource_type'])
+ self.assertEqual(resource_name, resource['logical_resource_id'])
+ self.assertEqual('CREATE_COMPLETE', resource['resource_status'])
+
+ def test_created_containers(self):
+ params = {'format': 'json'}
+ resp, container_list = \
+ self.account_client.list_account_containers(params=params)
+ self.assertEqual('200', resp['status'])
+ self.assertEqual(2, len(container_list))
+ for cont in container_list:
+ self.assertTrue(cont['name'].startswith(self.stack_name))
+
+ def test_acl(self):
+ acl_headers = ('x-container-meta-web-index', 'x-container-read')
+
+ swcont = self.test_resources.get(
+ 'SwiftContainer')['physical_resource_id']
+ swcont_website = self.test_resources.get(
+ 'SwiftContainerWebsite')['physical_resource_id']
+
+ headers, _ = self.container_client.list_container_metadata(swcont)
+ for h in acl_headers:
+ self.assertNotIn(h, headers)
+ headers, _ = self.container_client.list_container_metadata(
+ swcont_website)
+ for h in acl_headers:
+ self.assertIn(h, headers)
+
+ def test_metadata(self):
+ metadatas = {
+ "web-index": "index.html",
+ "web-error": "error.html"
+ }
+ swcont_website = self.test_resources.get(
+ 'SwiftContainerWebsite')['physical_resource_id']
+ headers, _ = self.container_client.list_container_metadata(
+ swcont_website)
+
+ for meta in metadatas:
+ header_meta = "x-container-meta-%s" % meta
+ self.assertIn(header_meta, headers)
+ self.assertEqual(headers[header_meta], metadatas[meta])
diff --git a/tempest/auth.py b/tempest/auth.py
index e1ba13b..8cb3b2c 100644
--- a/tempest/auth.py
+++ b/tempest/auth.py
@@ -382,7 +382,7 @@
path = "/" + filters['api_version']
noversion_path = "/".join(parts.path.split("/")[2:])
if noversion_path != "":
- path += noversion_path
+ path += "/" + noversion_path
_base_url = _base_url.replace(parts.path, path)
if filters.get('skip_path', None) is not None:
_base_url = _base_url.replace(parts.path, "/")
diff --git a/tempest/cli/simple_read_only/test_nova_manage.py b/tempest/cli/simple_read_only/test_nova_manage.py
index 13a1589..f1fee2e 100644
--- a/tempest/cli/simple_read_only/test_nova_manage.py
+++ b/tempest/cli/simple_read_only/test_nova_manage.py
@@ -41,6 +41,10 @@
if not CONF.service_available.nova:
msg = ("%s skipped as Nova is not available" % cls.__name__)
raise cls.skipException(msg)
+ if not CONF.cli.has_manage:
+ msg = ("%s skipped as *-manage commands not available"
+ % cls.__name__)
+ raise cls.skipException(msg)
super(SimpleReadOnlyNovaManageTest, cls).setUpClass()
def test_admin_fake_action(self):
diff --git a/tempest/common/generate_sample_tempest.py b/tempest/common/generate_sample_tempest.py
index e1213db..ceb3394 100644
--- a/tempest/common/generate_sample_tempest.py
+++ b/tempest/common/generate_sample_tempest.py
@@ -31,5 +31,5 @@
if __name__ == "__main__":
- CONF = tempest.config.TempestConfigPrivate(False)
+ tempest.config.register_opts()
generator.generate(sys.argv[1:])
diff --git a/tempest/common/glance_http.py b/tempest/common/glance_http.py
index 4503f13..b4ba933 100644
--- a/tempest/common/glance_http.py
+++ b/tempest/common/glance_http.py
@@ -21,6 +21,7 @@
import json
import posixpath
import re
+from six import moves
import socket
import StringIO
import struct
@@ -264,7 +265,7 @@
# Also try Subject Alternative Names for a match
san_list = None
- for i in xrange(x509.get_extension_count()):
+ for i in moves.xrange(x509.get_extension_count()):
ext = x509.get_extension(i)
if ext.get_short_name() == 'subjectAltName':
san_list = str(ext)
diff --git a/tempest/common/ssh.py b/tempest/common/ssh.py
index b6fa0a0..531887c 100644
--- a/tempest/common/ssh.py
+++ b/tempest/common/ssh.py
@@ -16,6 +16,7 @@
import cStringIO
import select
+import six
import socket
import time
import warnings
@@ -39,7 +40,7 @@
self.host = host
self.username = username
self.password = password
- if isinstance(pkey, basestring):
+ if isinstance(pkey, six.string_types):
pkey = paramiko.RSAKey.from_private_key(
cStringIO.StringIO(str(pkey)))
self.pkey = pkey
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 8fbbf82..8420ad0 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -11,6 +11,7 @@
# under the License.
import re
+import six
import time
from tempest.common import ssh
@@ -28,7 +29,7 @@
network = CONF.compute.network_for_ssh
ip_version = CONF.compute.ip_version_for_ssh
ssh_channel_timeout = CONF.compute.ssh_channel_timeout
- if isinstance(server, basestring):
+ if isinstance(server, six.string_types):
ip_address = server
else:
addresses = server['addresses'][network]
diff --git a/tempest/config.py b/tempest/config.py
index 4380608..0f5e23c 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -263,7 +263,11 @@
cfg.BoolOpt('block_migrate_cinder_iscsi',
default=False,
help="Does the test environment block migration support "
- "cinder iSCSI volumes")
+ "cinder iSCSI volumes"),
+ cfg.BoolOpt('vnc_console',
+ default=False,
+ help='Enable VNC console. This configuration value should '
+ 'be same as [nova.vnc]->vnc_enabled in nova.conf')
]
@@ -472,6 +476,9 @@
default='Member',
help="Role to add to users created for swift tests to "
"enable creating containers"),
+ cfg.StrOpt('reseller_admin_role',
+ default='ResellerAdmin',
+ help="User role that has reseller admin"),
]
object_storage_feature_group = cfg.OptGroup(
@@ -541,6 +548,11 @@
cfg.StrOpt('catalog_type',
default='metering',
help="Catalog type of the Telemetry service."),
+ cfg.StrOpt('endpoint_type',
+ default='publicURL',
+ choices=['public', 'admin', 'internal',
+ 'publicURL', 'adminURL', 'internalURL'],
+ help="The endpoint type to use for the telemetry service."),
]
@@ -563,7 +575,13 @@
DataProcessingGroup = [
cfg.StrOpt('catalog_type',
default='data_processing',
- help="Catalog type of the data processing service.")
+ help="Catalog type of the data processing service."),
+ cfg.StrOpt('endpoint_type',
+ default='publicURL',
+ choices=['public', 'admin', 'internal',
+ 'publicURL', 'adminURL', 'internalURL'],
+ help="The endpoint type to use for the data processing "
+ "service."),
]
@@ -761,6 +779,12 @@
cfg.StrOpt('catalog_type',
default='baremetal',
help="Catalog type of the baremetal provisioning service."),
+ cfg.StrOpt('endpoint_type',
+ default='publicURL',
+ choices=['public', 'admin', 'internal',
+ 'publicURL', 'adminURL', 'internalURL'],
+ help="The endpoint type to use for the baremetal provisioning "
+ "service."),
]
cli_group = cfg.OptGroup(name='cli', title="cli Configuration Options")
@@ -772,12 +796,52 @@
cfg.StrOpt('cli_dir',
default='/usr/local/bin',
help="directory where python client binaries are located"),
+ cfg.BoolOpt('has_manage',
+ default=True,
+ help=("Whether the tempest run location has access to the "
+ "*-manage commands. In a pure blackbox environment "
+ "it will not.")),
cfg.IntOpt('timeout',
default=15,
help="Number of seconds to wait on a CLI timeout"),
]
+def register_opts():
+ register_opt_group(cfg.CONF, compute_group, ComputeGroup)
+ register_opt_group(cfg.CONF, compute_features_group,
+ ComputeFeaturesGroup)
+ register_opt_group(cfg.CONF, identity_group, IdentityGroup)
+ register_opt_group(cfg.CONF, identity_feature_group,
+ IdentityFeatureGroup)
+ register_opt_group(cfg.CONF, image_group, ImageGroup)
+ register_opt_group(cfg.CONF, image_feature_group, ImageFeaturesGroup)
+ register_opt_group(cfg.CONF, network_group, NetworkGroup)
+ register_opt_group(cfg.CONF, network_feature_group,
+ NetworkFeaturesGroup)
+ register_opt_group(cfg.CONF, volume_group, VolumeGroup)
+ register_opt_group(cfg.CONF, volume_feature_group,
+ VolumeFeaturesGroup)
+ register_opt_group(cfg.CONF, object_storage_group, ObjectStoreGroup)
+ register_opt_group(cfg.CONF, object_storage_feature_group,
+ ObjectStoreFeaturesGroup)
+ register_opt_group(cfg.CONF, orchestration_group, OrchestrationGroup)
+ register_opt_group(cfg.CONF, telemetry_group, TelemetryGroup)
+ register_opt_group(cfg.CONF, dashboard_group, DashboardGroup)
+ register_opt_group(cfg.CONF, data_processing_group,
+ DataProcessingGroup)
+ register_opt_group(cfg.CONF, boto_group, BotoGroup)
+ register_opt_group(cfg.CONF, compute_admin_group, ComputeAdminGroup)
+ register_opt_group(cfg.CONF, stress_group, StressGroup)
+ register_opt_group(cfg.CONF, scenario_group, ScenarioGroup)
+ register_opt_group(cfg.CONF, service_available_group,
+ ServiceAvailableGroup)
+ register_opt_group(cfg.CONF, debug_group, DebugGroup)
+ register_opt_group(cfg.CONF, baremetal_group, BaremetalGroup)
+ register_opt_group(cfg.CONF, input_scenario_group, InputScenarioGroup)
+ register_opt_group(cfg.CONF, cli_group, CLIGroup)
+
+
# this should never be called outside of this class
class TempestConfigPrivate(object):
"""Provides OpenStack configuration information."""
@@ -788,64 +852,7 @@
DEFAULT_CONFIG_FILE = "tempest.conf"
- def __init__(self, parse_conf=True):
- """Initialize a configuration from a conf directory and conf file."""
- super(TempestConfigPrivate, self).__init__()
- config_files = []
- failsafe_path = "/etc/tempest/" + self.DEFAULT_CONFIG_FILE
-
- # Environment variables override defaults...
- conf_dir = os.environ.get('TEMPEST_CONFIG_DIR',
- self.DEFAULT_CONFIG_DIR)
- conf_file = os.environ.get('TEMPEST_CONFIG', self.DEFAULT_CONFIG_FILE)
-
- path = os.path.join(conf_dir, conf_file)
-
- if not os.path.isfile(path):
- path = failsafe_path
-
- # only parse the config file if we expect one to exist. This is needed
- # to remove an issue with the config file up to date checker.
- if parse_conf:
- config_files.append(path)
-
- cfg.CONF([], project='tempest', default_config_files=config_files)
- logging.setup('tempest')
- LOG = logging.getLogger('tempest')
- LOG.info("Using tempest config file %s" % path)
-
- register_opt_group(cfg.CONF, compute_group, ComputeGroup)
- register_opt_group(cfg.CONF, compute_features_group,
- ComputeFeaturesGroup)
- register_opt_group(cfg.CONF, identity_group, IdentityGroup)
- register_opt_group(cfg.CONF, identity_feature_group,
- IdentityFeatureGroup)
- register_opt_group(cfg.CONF, image_group, ImageGroup)
- register_opt_group(cfg.CONF, image_feature_group, ImageFeaturesGroup)
- register_opt_group(cfg.CONF, network_group, NetworkGroup)
- register_opt_group(cfg.CONF, network_feature_group,
- NetworkFeaturesGroup)
- register_opt_group(cfg.CONF, volume_group, VolumeGroup)
- register_opt_group(cfg.CONF, volume_feature_group,
- VolumeFeaturesGroup)
- register_opt_group(cfg.CONF, object_storage_group, ObjectStoreGroup)
- register_opt_group(cfg.CONF, object_storage_feature_group,
- ObjectStoreFeaturesGroup)
- register_opt_group(cfg.CONF, orchestration_group, OrchestrationGroup)
- register_opt_group(cfg.CONF, telemetry_group, TelemetryGroup)
- register_opt_group(cfg.CONF, dashboard_group, DashboardGroup)
- register_opt_group(cfg.CONF, data_processing_group,
- DataProcessingGroup)
- register_opt_group(cfg.CONF, boto_group, BotoGroup)
- register_opt_group(cfg.CONF, compute_admin_group, ComputeAdminGroup)
- register_opt_group(cfg.CONF, stress_group, StressGroup)
- register_opt_group(cfg.CONF, scenario_group, ScenarioGroup)
- register_opt_group(cfg.CONF, service_available_group,
- ServiceAvailableGroup)
- register_opt_group(cfg.CONF, debug_group, DebugGroup)
- register_opt_group(cfg.CONF, baremetal_group, BaremetalGroup)
- register_opt_group(cfg.CONF, input_scenario_group, InputScenarioGroup)
- register_opt_group(cfg.CONF, cli_group, CLIGroup)
+ def _set_attrs(self):
self.compute = cfg.CONF.compute
self.compute_feature_enabled = cfg.CONF['compute-feature-enabled']
self.identity = cfg.CONF.identity
@@ -877,6 +884,33 @@
self.compute_admin.password = self.identity.admin_password
self.compute_admin.tenant_name = self.identity.admin_tenant_name
+ def __init__(self, parse_conf=True):
+ """Initialize a configuration from a conf directory and conf file."""
+ super(TempestConfigPrivate, self).__init__()
+ config_files = []
+ failsafe_path = "/etc/tempest/" + self.DEFAULT_CONFIG_FILE
+
+ # Environment variables override defaults...
+ conf_dir = os.environ.get('TEMPEST_CONFIG_DIR',
+ self.DEFAULT_CONFIG_DIR)
+ conf_file = os.environ.get('TEMPEST_CONFIG', self.DEFAULT_CONFIG_FILE)
+
+ path = os.path.join(conf_dir, conf_file)
+
+ if not os.path.isfile(path):
+ path = failsafe_path
+
+ # only parse the config file if we expect one to exist. This is needed
+ # to remove an issue with the config file up to date checker.
+ if parse_conf:
+ config_files.append(path)
+
+ cfg.CONF([], project='tempest', default_config_files=config_files)
+ logging.setup('tempest')
+ LOG = logging.getLogger('tempest')
+ LOG.info("Using tempest config file %s" % path)
+ register_opts()
+ self._set_attrs()
if parse_conf:
cfg.CONF.log_opt_values(LOG, std_logging.DEBUG)
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 4c7542a..f06a850 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -16,6 +16,7 @@
import logging
import os
+import six
import subprocess
import netaddr
@@ -225,8 +226,9 @@
# so case sensitive comparisons can really mess things
# up.
if new_status.lower() == error_status.lower():
- message = ("%s failed to get to expected status. "
- "In %s state.") % (thing, new_status)
+ message = ("%s failed to get to expected status (%s). "
+ "In %s state.") % (thing, expected_status,
+ new_status)
raise exceptions.BuildErrorException(message,
server_id=thing_id)
elif new_status == expected_status and expected_status is not None:
@@ -290,6 +292,27 @@
image = CONF.compute.image_ref
if flavor is None:
flavor = CONF.compute.flavor_ref
+
+ fixed_network_name = CONF.compute.fixed_network_name
+ if 'nics' not in create_kwargs and fixed_network_name:
+ networks = client.networks.list()
+ # If several networks found, set the NetID on which to connect the
+ # server to avoid the following error "Multiple possible networks
+ # found, use a Network ID to be more specific."
+ # See Tempest #1250866
+ if len(networks) > 1:
+ for network in networks:
+ if network.label == fixed_network_name:
+ create_kwargs['nics'] = [{'net-id': network.id}]
+ break
+ # If we didn't find the network we were looking for :
+ else:
+ msg = ("The network on which the NIC of the server must "
+ "be connected can not be found : "
+ "fixed_network_name=%s. Starting instance without "
+ "specifying a network.") % fixed_network_name
+ LOG.info(msg)
+
LOG.debug("Creating a server (name: %s, image: %s, flavor: %s)",
name, image, flavor)
server = client.servers.create(name, image, flavor, **create_kwargs)
@@ -349,7 +372,7 @@
return keypair
def get_remote_client(self, server_or_ip, username=None, private_key=None):
- if isinstance(server_or_ip, basestring):
+ if isinstance(server_or_ip, six.string_types):
ip = server_or_ip
else:
network_name_for_ssh = CONF.compute.network_for_ssh
@@ -585,7 +608,7 @@
:param floating_ip: type DeletableFloatingIp
"""
floating_ip.update(port_id=None)
- self.assertEqual(None, floating_ip.port_id)
+ self.assertIsNone(floating_ip.port_id)
return floating_ip
def _ping_ip_address(self, ip_address, should_succeed=True):
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index 1144414..d369f12 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -26,10 +26,6 @@
LOG = logging.getLogger(__name__)
-# NOTE(andreaf) - nose does not honour the load_tests protocol
-# however it's test discovery regex will match anything
-# which includes _tests. So nose would require some further
-# investigation to be supported with this
load_tests = testscenarios.load_tests_apply_scenarios
diff --git a/tempest/services/compute/json/aggregates_client.py b/tempest/services/compute/json/aggregates_client.py
index e26f570..700a29b 100644
--- a/tempest/services/compute/json/aggregates_client.py
+++ b/tempest/services/compute/json/aggregates_client.py
@@ -15,14 +15,14 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
from tempest import exceptions
CONF = config.CONF
-class AggregatesClientJSON(RestClient):
+class AggregatesClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(AggregatesClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/availability_zone_client.py b/tempest/services/compute/json/availability_zone_client.py
index ea4e95e..9278d5b 100644
--- a/tempest/services/compute/json/availability_zone_client.py
+++ b/tempest/services/compute/json/availability_zone_client.py
@@ -15,13 +15,13 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class AvailabilityZoneClientJSON(RestClient):
+class AvailabilityZoneClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(AvailabilityZoneClientJSON, self).__init__(
diff --git a/tempest/services/compute/json/certificates_client.py b/tempest/services/compute/json/certificates_client.py
index de0f1a8..c05e352 100644
--- a/tempest/services/compute/json/certificates_client.py
+++ b/tempest/services/compute/json/certificates_client.py
@@ -15,13 +15,13 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class CertificatesClientJSON(RestClient):
+class CertificatesClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(CertificatesClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/extensions_client.py b/tempest/services/compute/json/extensions_client.py
index f7e2737..5ad8b98 100644
--- a/tempest/services/compute/json/extensions_client.py
+++ b/tempest/services/compute/json/extensions_client.py
@@ -15,13 +15,13 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class ExtensionsClientJSON(RestClient):
+class ExtensionsClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(ExtensionsClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/fixed_ips_client.py b/tempest/services/compute/json/fixed_ips_client.py
index af750a3..8b2c6c9 100644
--- a/tempest/services/compute/json/fixed_ips_client.py
+++ b/tempest/services/compute/json/fixed_ips_client.py
@@ -15,13 +15,13 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class FixedIPsClientJSON(RestClient):
+class FixedIPsClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(FixedIPsClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/flavors_client.py b/tempest/services/compute/json/flavors_client.py
index 289b09e..a8111af 100644
--- a/tempest/services/compute/json/flavors_client.py
+++ b/tempest/services/compute/json/flavors_client.py
@@ -16,13 +16,13 @@
import json
import urllib
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class FlavorsClientJSON(RestClient):
+class FlavorsClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(FlavorsClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/floating_ips_client.py b/tempest/services/compute/json/floating_ips_client.py
index 0385160..42487c3 100644
--- a/tempest/services/compute/json/floating_ips_client.py
+++ b/tempest/services/compute/json/floating_ips_client.py
@@ -16,14 +16,14 @@
import json
import urllib
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
from tempest import exceptions
CONF = config.CONF
-class FloatingIPsClientJSON(RestClient):
+class FloatingIPsClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(FloatingIPsClientJSON, self).__init__(auth_provider)
self.service = CONF.compute.catalog_type
diff --git a/tempest/services/compute/json/hosts_client.py b/tempest/services/compute/json/hosts_client.py
index d826a78..fb45997 100644
--- a/tempest/services/compute/json/hosts_client.py
+++ b/tempest/services/compute/json/hosts_client.py
@@ -15,13 +15,13 @@
import json
import urllib
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class HostsClientJSON(RestClient):
+class HostsClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(HostsClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/hypervisor_client.py b/tempest/services/compute/json/hypervisor_client.py
index 74844dc..c6b13b0 100644
--- a/tempest/services/compute/json/hypervisor_client.py
+++ b/tempest/services/compute/json/hypervisor_client.py
@@ -15,13 +15,13 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class HypervisorClientJSON(RestClient):
+class HypervisorClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(HypervisorClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/images_client.py b/tempest/services/compute/json/images_client.py
index b3d8c35..5a79a29 100644
--- a/tempest/services/compute/json/images_client.py
+++ b/tempest/services/compute/json/images_client.py
@@ -16,7 +16,7 @@
import json
import urllib
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest.common import waiters
from tempest import config
from tempest import exceptions
@@ -24,7 +24,7 @@
CONF = config.CONF
-class ImagesClientJSON(RestClient):
+class ImagesClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(ImagesClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/instance_usage_audit_log_client.py b/tempest/services/compute/json/instance_usage_audit_log_client.py
index 27930f2..1f6e988 100644
--- a/tempest/services/compute/json/instance_usage_audit_log_client.py
+++ b/tempest/services/compute/json/instance_usage_audit_log_client.py
@@ -15,13 +15,13 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class InstanceUsagesAuditLogClientJSON(RestClient):
+class InstanceUsagesAuditLogClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(InstanceUsagesAuditLogClientJSON, self).__init__(
diff --git a/tempest/services/compute/json/interfaces_client.py b/tempest/services/compute/json/interfaces_client.py
index f4c4c64..9928b94 100644
--- a/tempest/services/compute/json/interfaces_client.py
+++ b/tempest/services/compute/json/interfaces_client.py
@@ -16,14 +16,14 @@
import json
import time
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
from tempest import exceptions
CONF = config.CONF
-class InterfacesClientJSON(RestClient):
+class InterfacesClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(InterfacesClientJSON, self).__init__(auth_provider)
@@ -80,3 +80,25 @@
raise exceptions.TimeoutException(message)
return resp, body
+
+ def add_fixed_ip(self, server_id, network_id):
+ """Add a fixed IP to input server instance."""
+ post_body = json.dumps({
+ 'addFixedIp': {
+ 'networkId': network_id
+ }
+ })
+ resp, body = self.post('servers/%s/action' % str(server_id),
+ post_body)
+ return resp, body
+
+ def remove_fixed_ip(self, server_id, ip_address):
+ """Remove input fixed IP from input server instance."""
+ post_body = json.dumps({
+ 'removeFixedIp': {
+ 'address': ip_address
+ }
+ })
+ resp, body = self.post('servers/%s/action' % str(server_id),
+ post_body)
+ return resp, body
diff --git a/tempest/services/compute/json/keypairs_client.py b/tempest/services/compute/json/keypairs_client.py
index 356c2e6..28f3c31 100644
--- a/tempest/services/compute/json/keypairs_client.py
+++ b/tempest/services/compute/json/keypairs_client.py
@@ -15,13 +15,13 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class KeyPairsClientJSON(RestClient):
+class KeyPairsClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(KeyPairsClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/limits_client.py b/tempest/services/compute/json/limits_client.py
index 765ba79..1493718 100644
--- a/tempest/services/compute/json/limits_client.py
+++ b/tempest/services/compute/json/limits_client.py
@@ -15,13 +15,13 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class LimitsClientJSON(RestClient):
+class LimitsClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(LimitsClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/quotas_client.py b/tempest/services/compute/json/quotas_client.py
index 7607cc0..459ab6d 100644
--- a/tempest/services/compute/json/quotas_client.py
+++ b/tempest/services/compute/json/quotas_client.py
@@ -15,13 +15,13 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class QuotasClientJSON(RestClient):
+class QuotasClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(QuotasClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/security_groups_client.py b/tempest/services/compute/json/security_groups_client.py
index 2cd2d2e..899d4ef 100644
--- a/tempest/services/compute/json/security_groups_client.py
+++ b/tempest/services/compute/json/security_groups_client.py
@@ -16,14 +16,14 @@
import json
import urllib
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
from tempest import exceptions
CONF = config.CONF
-class SecurityGroupsClientJSON(RestClient):
+class SecurityGroupsClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(SecurityGroupsClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/servers_client.py b/tempest/services/compute/json/servers_client.py
index 025c4e5..623bf42 100644
--- a/tempest/services/compute/json/servers_client.py
+++ b/tempest/services/compute/json/servers_client.py
@@ -18,7 +18,7 @@
import time
import urllib
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest.common import waiters
from tempest import config
from tempest import exceptions
@@ -26,7 +26,7 @@
CONF = config.CONF
-class ServersClientJSON(RestClient):
+class ServersClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(ServersClientJSON, self).__init__(auth_provider)
@@ -428,3 +428,11 @@
def restore_soft_deleted_server(self, server_id, **kwargs):
"""Restore a soft-deleted server."""
return self.action(server_id, 'restore', None, **kwargs)
+
+ def reset_network(self, server_id, **kwargs):
+ """Resets the Network of a server"""
+ return self.action(server_id, 'resetNetwork', None, **kwargs)
+
+ def inject_network_info(self, server_id, **kwargs):
+ """Inject the Network Info into server"""
+ return self.action(server_id, 'injectNetworkInfo', None, **kwargs)
diff --git a/tempest/services/compute/json/services_client.py b/tempest/services/compute/json/services_client.py
index 8380dc2..1ab25ec 100644
--- a/tempest/services/compute/json/services_client.py
+++ b/tempest/services/compute/json/services_client.py
@@ -17,13 +17,13 @@
import json
import urllib
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class ServicesClientJSON(RestClient):
+class ServicesClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(ServicesClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/tenant_usages_client.py b/tempest/services/compute/json/tenant_usages_client.py
index b14fa9b..f3a67dd 100644
--- a/tempest/services/compute/json/tenant_usages_client.py
+++ b/tempest/services/compute/json/tenant_usages_client.py
@@ -16,13 +16,13 @@
import json
import urllib
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class TenantUsagesClientJSON(RestClient):
+class TenantUsagesClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(TenantUsagesClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/volumes_extensions_client.py b/tempest/services/compute/json/volumes_extensions_client.py
index 4b9dc0b..5ef11ed 100644
--- a/tempest/services/compute/json/volumes_extensions_client.py
+++ b/tempest/services/compute/json/volumes_extensions_client.py
@@ -17,14 +17,14 @@
import time
import urllib
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
from tempest import exceptions
CONF = config.CONF
-class VolumesExtensionsClientJSON(RestClient):
+class VolumesExtensionsClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(VolumesExtensionsClientJSON, self).__init__(
diff --git a/tempest/services/compute/v3/json/interfaces_client.py b/tempest/services/compute/v3/json/interfaces_client.py
index c167520..f8b9d09 100644
--- a/tempest/services/compute/v3/json/interfaces_client.py
+++ b/tempest/services/compute/v3/json/interfaces_client.py
@@ -81,3 +81,25 @@
raise exceptions.TimeoutException(message)
return resp, body
+
+ def add_fixed_ip(self, server_id, network_id):
+ """Add a fixed IP to input server instance."""
+ post_body = json.dumps({
+ 'add_fixed_ip': {
+ 'network_id': network_id
+ }
+ })
+ resp, body = self.post('servers/%s/action' % str(server_id),
+ post_body)
+ return resp, body
+
+ def remove_fixed_ip(self, server_id, ip_address):
+ """Remove input fixed IP from input server instance."""
+ post_body = json.dumps({
+ 'remove_fixed_ip': {
+ 'address': ip_address
+ }
+ })
+ resp, body = self.post('servers/%s/action' % str(server_id),
+ post_body)
+ return resp, body
diff --git a/tempest/services/compute/v3/json/servers_client.py b/tempest/services/compute/v3/json/servers_client.py
index 840e914..819e366 100644
--- a/tempest/services/compute/v3/json/servers_client.py
+++ b/tempest/services/compute/v3/json/servers_client.py
@@ -423,3 +423,15 @@
def restore_soft_deleted_server(self, server_id, **kwargs):
"""Restore a soft-deleted server."""
return self.action(server_id, 'restore', None, **kwargs)
+
+ def get_vnc_console(self, server_id, type):
+ """Get URL of VNC console."""
+ post_body = json.dumps({
+ "get_vnc_console": {
+ "type": type
+ }
+ })
+ resp, body = self.post('servers/%s/action' % str(server_id),
+ post_body)
+ body = json.loads(body)
+ return resp, body['console']
diff --git a/tempest/services/compute/xml/common.py b/tempest/services/compute/xml/common.py
index 4def19f..b29b932 100644
--- a/tempest/services/compute/xml/common.py
+++ b/tempest/services/compute/xml/common.py
@@ -18,6 +18,11 @@
XMLNS_11 = "http://docs.openstack.org/compute/api/v1.1"
XMLNS_V3 = "http://docs.openstack.org/compute/api/v1.1"
+NEUTRON_NAMESPACES = {
+ 'router': "http://docs.openstack.org/ext/neutron/router/api/v1.0",
+ 'provider': 'http://docs.openstack.org/ext/provider/api/v1.0',
+}
+
# NOTE(danms): This is just a silly implementation to help make generating
# XML faster for prototyping. Could be replaced with proper etree gorp
@@ -137,6 +142,9 @@
tag = child.tag
if tag.startswith("{"):
ns, tag = tag.split("}", 1)
+ for key, uri in NEUTRON_NAMESPACES.iteritems():
+ if uri == ns[1:]:
+ tag = key + ":" + tag
if plurals is not None and tag in plurals:
json[tag] = parse_array(child, plurals)
else:
diff --git a/tempest/services/compute/xml/interfaces_client.py b/tempest/services/compute/xml/interfaces_client.py
index 5df6187..8d4bfcc 100644
--- a/tempest/services/compute/xml/interfaces_client.py
+++ b/tempest/services/compute/xml/interfaces_client.py
@@ -24,6 +24,7 @@
from tempest.services.compute.xml.common import Element
from tempest.services.compute.xml.common import Text
from tempest.services.compute.xml.common import xml_to_json
+from tempest.services.compute.xml.common import XMLNS_11
CONF = config.CONF
@@ -104,3 +105,21 @@
(port_id, status, self.build_timeout))
raise exceptions.TimeoutException(message)
return resp, body
+
+ def add_fixed_ip(self, server_id, network_id):
+ """Add a fixed IP to input server instance."""
+ post_body = Element("addFixedIp",
+ xmlns=XMLNS_11,
+ networkId=network_id)
+ resp, body = self.post('servers/%s/action' % str(server_id),
+ str(Document(post_body)))
+ return resp, body
+
+ def remove_fixed_ip(self, server_id, ip_address):
+ """Remove input fixed IP from input server instance."""
+ post_body = Element("removeFixedIp",
+ xmlns=XMLNS_11,
+ address=ip_address)
+ resp, body = self.post('servers/%s/action' % str(server_id),
+ str(Document(post_body)))
+ return resp, body
diff --git a/tempest/services/compute/xml/quotas_client.py b/tempest/services/compute/xml/quotas_client.py
index eb287c2..b8b759f 100644
--- a/tempest/services/compute/xml/quotas_client.py
+++ b/tempest/services/compute/xml/quotas_client.py
@@ -44,9 +44,6 @@
return quota
- def _parse_array(self, node):
- return [self._format_quota(xml_to_json(x)) for x in node]
-
def get_quota_set(self, tenant_id):
"""List the quota set for a tenant."""
diff --git a/tempest/services/compute/xml/servers_client.py b/tempest/services/compute/xml/servers_client.py
index da01b83..cd2cb06 100644
--- a/tempest/services/compute/xml/servers_client.py
+++ b/tempest/services/compute/xml/servers_client.py
@@ -633,3 +633,11 @@
def restore_soft_deleted_server(self, server_id, **kwargs):
"""Restore a soft-deleted server."""
return self.action(server_id, 'restore', None, **kwargs)
+
+ def reset_network(self, server_id, **kwargs):
+ """Resets the Network of a server"""
+ return self.action(server_id, 'resetNetwork', None, **kwargs)
+
+ def inject_network_info(self, server_id, **kwargs):
+ """Inject the Network Info into server"""
+ return self.action(server_id, 'injectNetworkInfo', None, **kwargs)
diff --git a/tempest/services/identity/v3/xml/endpoints_client.py b/tempest/services/identity/v3/xml/endpoints_client.py
index a32eede..d79ea92 100644
--- a/tempest/services/identity/v3/xml/endpoints_client.py
+++ b/tempest/services/identity/v3/xml/endpoints_client.py
@@ -67,6 +67,8 @@
"""Create endpoint."""
region = kwargs.get('region', None)
enabled = kwargs.get('enabled', None)
+ if enabled is not None:
+ enabled = str(enabled).lower()
create_endpoint = Element("endpoint",
xmlns=XMLNS,
service_id=service_id,
@@ -93,7 +95,7 @@
if region:
endpoint.add_attr("region", region)
if enabled is not None:
- endpoint.add_attr("enabled", enabled)
+ endpoint.add_attr("enabled", str(enabled).lower())
resp, body = self.patch('endpoints/%s' % str(endpoint_id), str(doc))
body = self._parse_body(etree.fromstring(body))
return resp, body
diff --git a/tempest/services/identity/v3/xml/service_client.py b/tempest/services/identity/v3/xml/service_client.py
index d5476c4..d4a5877 100644
--- a/tempest/services/identity/v3/xml/service_client.py
+++ b/tempest/services/identity/v3/xml/service_client.py
@@ -35,12 +35,6 @@
self.endpoint_url = 'adminURL'
self.api_version = "v3"
- def _parse_array(self, node):
- array = []
- for child in node.getchildren():
- array.append(xml_to_json(child))
- return array
-
def _parse_body(self, body):
data = xml_to_json(body)
return data
diff --git a/tempest/services/image/v2/json/image_client.py b/tempest/services/image/v2/json/image_client.py
index 58819d0..b3014fc 100644
--- a/tempest/services/image/v2/json/image_client.py
+++ b/tempest/services/image/v2/json/image_client.py
@@ -39,23 +39,9 @@
filters=self.filters,
insecure=dscv)
- def get_images_schema(self):
- url = 'v2/schemas/images'
- resp, body = self.get(url)
- body = json.loads(body)
- return resp, body
-
- def get_image_schema(self):
- url = 'v2/schemas/image'
- resp, body = self.get(url)
- body = json.loads(body)
- return resp, body
-
def _validate_schema(self, body, type='image'):
- if type == 'image':
- resp, schema = self.get_image_schema()
- elif type == 'images':
- resp, schema = self.get_images_schema()
+ if type in ['image', 'images']:
+ resp, schema = self.get_schema(type)
else:
raise ValueError("%s is not a valid schema type" % type)
@@ -68,6 +54,15 @@
self._http = self._get_http()
return self._http
+ def update_image(self, image_id, patch):
+ data = json.dumps(patch)
+ self._validate_schema(data)
+
+ headers = {"Content-Type": "application/openstack-images-v2.0"
+ "-json-patch"}
+ resp, body = self.patch('v2/images/%s' % image_id, data, headers)
+ return resp, self._parse_resp(body)
+
def create_image(self, name, container_format, disk_format, **kwargs):
params = {
"name": name,
@@ -163,3 +158,21 @@
body = json.loads(body)
self.expected_success(200, resp)
return resp, body
+
+ def get_member(self, image_id, member_id):
+ url = 'v2/images/%s/members/%s' % (image_id, member_id)
+ resp, body = self.get(url)
+ self.expected_success(200, resp)
+ return resp, json.loads(body)
+
+ def remove_member(self, image_id, member_id):
+ url = 'v2/images/%s/members/%s' % (image_id, member_id)
+ resp, _ = self.delete(url)
+ self.expected_success(204, resp)
+ return resp
+
+ def get_schema(self, schema):
+ url = 'v2/schemas/%s' % schema
+ resp, body = self.get(url)
+ body = json.loads(body)
+ return resp, body
diff --git a/tempest/services/network/json/network_client.py b/tempest/services/network/json/network_client.py
index 81dbfbc..366ccee 100644
--- a/tempest/services/network/json/network_client.py
+++ b/tempest/services/network/json/network_client.py
@@ -154,20 +154,6 @@
body = json.loads(body)
return resp, body
- def create_security_group(self, name, **kwargs):
- post_body = {
- 'security_group': {
- 'name': name,
- }
- }
- for key, value in kwargs.iteritems():
- post_body['security_group'][str(key)] = value
- body = json.dumps(post_body)
- uri = '%s/security-groups' % (self.uri_prefix)
- resp, body = self.post(uri, body)
- body = json.loads(body)
- return resp, body
-
def update_floating_ip(self, floating_ip_id, **kwargs):
post_body = {
'floatingip': kwargs}
@@ -177,22 +163,6 @@
body = json.loads(body)
return resp, body
- def create_security_group_rule(self, secgroup_id,
- direction='ingress', **kwargs):
- post_body = {
- 'security_group_rule': {
- 'direction': direction,
- 'security_group_id': secgroup_id
- }
- }
- for key, value in kwargs.iteritems():
- post_body['security_group_rule'][str(key)] = value
- body = json.dumps(post_body)
- uri = '%s/security-group-rules' % (self.uri_prefix)
- resp, body = self.post(uri, body)
- body = json.loads(body)
- return resp, body
-
def create_member(self, address, protocol_port, pool_id):
post_body = {
"member": {
diff --git a/tempest/services/network/xml/network_client.py b/tempest/services/network/xml/network_client.py
index 25e6edb..8152d71 100644
--- a/tempest/services/network/xml/network_client.py
+++ b/tempest/services/network/xml/network_client.py
@@ -30,12 +30,6 @@
rc.TYPE = self.TYPE
return rc
- def _parse_array(self, node):
- array = []
- for child in node.getchildren():
- array.append(common.xml_to_json(child))
- return array
-
def deserialize_list(self, body):
return common.parse_array(etree.fromstring(body), self.PLURALS)
@@ -49,9 +43,14 @@
post_body = common.Element(root)
post_body.add_attr('xmlns:xsi',
'http://www.w3.org/2001/XMLSchema-instance')
+ elements = set()
for name, attr in body[root].items():
elt = self._get_element(name, attr)
post_body.append(elt)
+ if ":" in name:
+ elements.add(name.split(":")[0])
+ if elements:
+ self._add_namespaces(post_body, elements)
return str(common.Document(post_body))
def serialize_list(self, body, root_name=None, item_name=None):
@@ -88,29 +87,10 @@
else:
return common.Element(name, value)
- def create_security_group(self, name):
- uri = '%s/security-groups' % (self.uri_prefix)
- post_body = common.Element("security_group")
- p2 = common.Element("name", name)
- post_body.append(p2)
- resp, body = self.post(uri, str(common.Document(post_body)))
- body = _root_tag_fetcher_and_xml_to_json_parse(body)
- return resp, body
-
- def create_security_group_rule(self, secgroup_id,
- direction='ingress', **kwargs):
- uri = '%s/security-group-rules' % (self.uri_prefix)
- rule = common.Element("security_group_rule")
- p1 = common.Element('security_group_id', secgroup_id)
- p2 = common.Element('direction', direction)
- rule.append(p1)
- rule.append(p2)
- for key, val in kwargs.items():
- key = common.Element(key, val)
- rule.append(key)
- resp, body = self.post(uri, str(common.Document(rule)))
- body = _root_tag_fetcher_and_xml_to_json_parse(body)
- return resp, body
+ def _add_namespaces(self, root, elements):
+ for element in elements:
+ root.add_attr('xmlns:%s' % element,
+ common.NEUTRON_NAMESPACES[element])
def create_member(self, address, protocol_port, pool_id):
uri = '%s/lb/members' % (self.uri_prefix)
diff --git a/tempest/stress/driver.py b/tempest/stress/driver.py
index 3715636..9660081 100644
--- a/tempest/stress/driver.py
+++ b/tempest/stress/driver.py
@@ -17,6 +17,8 @@
import signal
import time
+from six import moves
+
from tempest import clients
from tempest.common import ssh
from tempest.common.utils import data_utils
@@ -128,7 +130,7 @@
manager = admin_manager
else:
manager = clients.Manager()
- for p_number in xrange(test.get('threads', default_thread_num)):
+ for p_number in moves.xrange(test.get('threads', default_thread_num)):
if test.get('use_isolated_tenants', False):
username = data_utils.rand_name("stress_user")
tenant_name = data_utils.rand_name("stress_tenant")
diff --git a/tempest/test.py b/tempest/test.py
index 22aa3f2..c6e3d6e 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -23,7 +23,6 @@
import uuid
import fixtures
-import nose.plugins.attrib
import testresources
import testtools
@@ -43,11 +42,10 @@
def attr(*args, **kwargs):
- """A decorator which applies the nose and testtools attr decorator
+ """A decorator which applies the testtools attr decorator
- This decorator applies the nose attr decorator as well as the
- the testtools.testcase.attr if it is in the list of attributes
- to testtools we want to apply.
+ This decorator applies the testtools.testcase.attr if it is in the list of
+ attributes to testtools we want to apply.
"""
def decorator(f):
@@ -60,7 +58,7 @@
f = testtools.testcase.attr(attr)(f)
if attr == 'smoke':
f = testtools.testcase.attr('gate')(f)
- return nose.plugins.attrib.attr(*args, **kwargs)(f)
+ return f
return decorator
@@ -194,40 +192,6 @@
return True
return False
-# there is a mis-match between nose and testtools for older pythons.
-# testtools will set skipException to be either
-# unittest.case.SkipTest, unittest2.case.SkipTest or an internal skip
-# exception, depending on what it can find. Python <2.7 doesn't have
-# unittest.case.SkipTest; so if unittest2 is not installed it falls
-# back to the internal class.
-#
-# The current nose skip plugin will decide to raise either
-# unittest.case.SkipTest or its own internal exception; it does not
-# look for unittest2 or the internal unittest exception. Thus we must
-# monkey-patch testtools.TestCase.skipException to be the exception
-# the nose skip plugin expects.
-#
-# However, with the switch to testr nose may not be available, so we
-# require you to opt-in to this fix with an environment variable.
-#
-# This is temporary until upstream nose starts looking for unittest2
-# as testtools does; we can then remove this and ensure unittest2 is
-# available for older pythons; then nose and testtools will agree
-# unittest2.case.SkipTest is the one-true skip test exception.
-#
-# https://review.openstack.org/#/c/33056
-# https://github.com/nose-devs/nose/pull/699
-if 'TEMPEST_PY26_NOSE_COMPAT' in os.environ:
- try:
- import unittest.case.SkipTest
- # convince pep8 we're using the import...
- if unittest.case.SkipTest:
- pass
- raise RuntimeError("You have unittest.case.SkipTest; "
- "no need to override")
- except ImportError:
- LOG.info("Overriding skipException to nose SkipTest")
- testtools.TestCase.skipException = nose.plugins.skip.SkipTest
at_exit_set = set()
diff --git a/tempest/tests/test_decorators.py b/tempest/tests/test_decorators.py
index 88920dc..aa3c8fc 100644
--- a/tempest/tests/test_decorators.py
+++ b/tempest/tests/test_decorators.py
@@ -41,10 +41,6 @@
self.assertEqual(getattr(foo, '__testtools_attrs'),
set(expected_attrs))
- # nose sets it anyway
- for arg, value in decorator_args.items():
- self.assertEqual(getattr(foo, arg), value)
-
def test_attr_without_type(self):
self._test_attr_helper(expected_attrs='baz', bar='baz')
@@ -74,7 +70,6 @@
t = TestFoo('test_bar')
self.assertEqual(set(decorator_args), getattr(t.test_bar,
'__testtools_attrs'))
- self.assertEqual(list(decorator_args), t.test_bar.type)
self.assertEqual(t.test_bar(), 0)
def test_services_decorator_with_single_service(self):
@@ -110,7 +105,6 @@
expected_frequency)
self.assertEqual(getattr(foo, 'st_allow_inheritance'),
expected_inheritance)
- self.assertEqual(foo.type, 'stress')
self.assertEqual(set(['stress']), getattr(foo, '__testtools_attrs'))
def test_stresstest_decorator_default(self):
diff --git a/tempest/tests/test_rest_client.py b/tempest/tests/test_rest_client.py
index ba43daf..9f07972 100644
--- a/tempest/tests/test_rest_client.py
+++ b/tempest/tests/test_rest_client.py
@@ -164,7 +164,7 @@
keys = ["fake_key1", "fake_key2"]
values = ["fake_value1", "fake_value2"]
- item_expected = {key: value for key, value in zip(keys, values)}
+ item_expected = dict((key, value) for (key, value) in zip(keys, values))
list_expected = {"body_list": [
{keys[0]: values[0]},
{keys[1]: values[1]},
diff --git a/tempest/thirdparty/boto/test.py b/tempest/thirdparty/boto/test.py
index b36e8c7..10d421e 100644
--- a/tempest/thirdparty/boto/test.py
+++ b/tempest/thirdparty/boto/test.py
@@ -17,6 +17,7 @@
import logging as orig_logging
import os
import re
+import six
import urlparse
import boto
@@ -26,14 +27,12 @@
import keystoneclient.exceptions
import tempest.clients
-from tempest.common.utils.file_utils import have_effective_read_access
+from tempest.common.utils import file_utils
from tempest import config
from tempest import exceptions
from tempest.openstack.common import log as logging
import tempest.test
-from tempest.thirdparty.boto.utils.wait import re_search_wait
-from tempest.thirdparty.boto.utils.wait import state_wait
-from tempest.thirdparty.boto.utils.wait import wait_exception
+from tempest.thirdparty.boto.utils import wait
CONF = config.CONF
LOG = logging.getLogger(__name__)
@@ -47,7 +46,7 @@
id_matcher = re.compile("[A-Za-z0-9]{20,}")
def all_read(*args):
- return all(map(have_effective_read_access, args))
+ return all(map(file_utils.have_effective_read_access, args))
materials_path = CONF.boto.s3_materials_path
ami_path = materials_path + os.sep + CONF.boto.ami_manifest
@@ -136,7 +135,7 @@
The not leaf elements does wildcard match
"""
# in error_code just literal and '.' characters expected
- if not isinstance(error_data, basestring):
+ if not isinstance(error_data, six.string_types):
(error_code, status_code) = map(str, error_data)
else:
status_code = None
@@ -146,7 +145,7 @@
num_parts = len(parts)
max_index = num_parts - 1
add_cls = error_cls
- for i_part in xrange(num_parts):
+ for i_part in six.moves.xrange(num_parts):
part = parts[i_part]
leaf = i_part == max_index
if not leaf:
@@ -327,7 +326,7 @@
final_set = set((final_set,))
final_set |= self.gone_set
lfunction = self.get_lfunction_gone(lfunction)
- state = state_wait(lfunction, final_set, valid_set)
+ state = wait.state_wait(lfunction, final_set, valid_set)
self.assertIn(state, valid_set | self.gone_set)
return state
@@ -377,8 +376,8 @@
return "ASSOCIATED"
return "DISASSOCIATED"
- state = state_wait(_disassociate, "DISASSOCIATED",
- set(("ASSOCIATED", "DISASSOCIATED")))
+ state = wait.state_wait(_disassociate, "DISASSOCIATED",
+ set(("ASSOCIATED", "DISASSOCIATED")))
self.assertEqual(state, "DISASSOCIATED")
def assertAddressReleasedWait(self, address):
@@ -391,7 +390,7 @@
return "DELETED"
return "NOTDELETED"
- state = state_wait(_address_delete, "DELETED")
+ state = wait.state_wait(_address_delete, "DELETED")
self.assertEqual(state, "DELETED")
def assertReSearch(self, regexp, string):
@@ -462,7 +461,7 @@
for instance in reservation.instances:
try:
instance.terminate()
- re_search_wait(_instance_state, "_GONE")
+ wait.re_search_wait(_instance_state, "_GONE")
except BaseException:
LOG.exception("Failed to terminate instance %s " % instance)
exc_num += 1
@@ -503,7 +502,8 @@
return volume.status
try:
- re_search_wait(_volume_state, "available") # not validates status
+ wait.re_search_wait(_volume_state, "available")
+ # not validates status
LOG.info(_volume_state())
volume.delete()
except BaseException:
@@ -520,7 +520,7 @@
def _update():
snapshot.update(validate=True)
- wait_exception(_update)
+ wait.wait_exception(_update)
# you can specify tuples if you want to specify the status pattern
diff --git a/tempest/thirdparty/boto/test_ec2_instance_run.py b/tempest/thirdparty/boto/test_ec2_instance_run.py
index 54861be..bbfbb79 100644
--- a/tempest/thirdparty/boto/test_ec2_instance_run.py
+++ b/tempest/thirdparty/boto/test_ec2_instance_run.py
@@ -16,23 +16,21 @@
from boto import exception
from tempest.common.utils import data_utils
-from tempest.common.utils.linux.remote_client import RemoteClient
+from tempest.common.utils.linux import remote_client
from tempest import config
from tempest import exceptions
from tempest.openstack.common import log as logging
-from tempest.test import attr
-from tempest.test import skip_because
-from tempest.thirdparty.boto.test import BotoTestCase
-from tempest.thirdparty.boto.utils.s3 import s3_upload_dir
-from tempest.thirdparty.boto.utils.wait import re_search_wait
-from tempest.thirdparty.boto.utils.wait import state_wait
+from tempest import test
+from tempest.thirdparty.boto import test as boto_test
+from tempest.thirdparty.boto.utils import s3
+from tempest.thirdparty.boto.utils import wait
CONF = config.CONF
LOG = logging.getLogger(__name__)
-class InstanceRunTest(BotoTestCase):
+class InstanceRunTest(boto_test.BotoTestCase):
@classmethod
def setUpClass(cls):
@@ -57,7 +55,7 @@
cls.addResourceCleanUp(cls.destroy_bucket,
cls.s3_client.connection_data,
cls.bucket_name)
- s3_upload_dir(bucket, cls.materials_path)
+ s3.s3_upload_dir(bucket, cls.materials_path)
cls.images = {"ami":
{"name": data_utils.rand_name("ami-name-"),
"location": cls.bucket_name + "/" + ami_manifest},
@@ -78,14 +76,14 @@
def _state():
retr = cls.ec2_client.get_image(image["image_id"])
return retr.state
- state = state_wait(_state, "available")
+ state = wait.state_wait(_state, "available")
if state != "available":
for _image in cls.images.itervalues():
cls.ec2_client.deregister_image(_image["image_id"])
raise exceptions.EC2RegisterImageException(image_id=
image["image_id"])
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_run_idempotent_instances(self):
# EC2 run instances idempotently
@@ -123,7 +121,7 @@
_terminate_reservation(reservation_1, rcuk_1)
_terminate_reservation(reservation_2, rcuk_2)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_run_stop_terminate_instance(self):
# EC2 run, stop and terminate instance
image_ami = self.ec2_client.get_image(self.images["ami"]
@@ -148,7 +146,7 @@
instance.terminate()
self.cancelResourceCleanUp(rcuk)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_run_stop_terminate_instance_with_tags(self):
# EC2 run, stop and terminate instance with tags
image_ami = self.ec2_client.get_image(self.images["ami"]
@@ -195,8 +193,8 @@
instance.terminate()
self.cancelResourceCleanUp(rcuk)
- @skip_because(bug="1098891")
- @attr(type='smoke')
+ @test.skip_because(bug="1098891")
+ @test.attr(type='smoke')
def test_run_terminate_instance(self):
# EC2 run, terminate immediately
image_ami = self.ec2_client.get_image(self.images["ami"]
@@ -222,8 +220,8 @@
# NOTE(afazekas): doctored test case,
# with normal validation it would fail
- @skip_because(bug="1182679")
- @attr(type='smoke')
+ @test.skip_because(bug="1182679")
+ @test.attr(type='smoke')
def test_integration_1(self):
# EC2 1. integration test (not strict)
image_ami = self.ec2_client.get_image(self.images["ami"]["image_id"])
@@ -271,9 +269,9 @@
self.assertVolumeStatusWait(volume, "available")
# NOTE(afazekas): it may be reports available before it is available
- ssh = RemoteClient(address.public_ip,
- CONF.compute.ssh_user,
- pkey=self.keypair.material)
+ ssh = remote_client.RemoteClient(address.public_ip,
+ CONF.compute.ssh_user,
+ pkey=self.keypair.material)
text = data_utils.rand_name("Pattern text for console output -")
resp = ssh.write_to_console(text)
self.assertFalse(resp)
@@ -282,7 +280,7 @@
output = instance.get_console_output()
return output.output
- re_search_wait(_output, text)
+ wait.re_search_wait(_output, text)
part_lines = ssh.get_partitions().split('\n')
volume.attach(instance.id, "/dev/vdh")
@@ -291,7 +289,7 @@
return volume.status
self.assertVolumeStatusWait(_volume_state, "in-use")
- re_search_wait(_volume_state, "in-use")
+ wait.re_search_wait(_volume_state, "in-use")
# NOTE(afazekas): Different Hypervisor backends names
# differently the devices,
@@ -305,7 +303,7 @@
return 'DECREASE'
return 'EQUAL'
- state_wait(_part_state, 'INCREASE')
+ wait.state_wait(_part_state, 'INCREASE')
part_lines = ssh.get_partitions().split('\n')
# TODO(afazekas): Resource compare to the flavor settings
@@ -313,10 +311,10 @@
volume.detach()
self.assertVolumeStatusWait(_volume_state, "available")
- re_search_wait(_volume_state, "available")
+ wait.re_search_wait(_volume_state, "available")
LOG.info("Volume %s state: %s", volume.id, volume.status)
- state_wait(_part_state, 'DECREASE')
+ wait.state_wait(_part_state, 'DECREASE')
instance.stop()
address.disassociate()
diff --git a/tempest/thirdparty/boto/test_ec2_keys.py b/tempest/thirdparty/boto/test_ec2_keys.py
index 329ace3..dec0170 100644
--- a/tempest/thirdparty/boto/test_ec2_keys.py
+++ b/tempest/thirdparty/boto/test_ec2_keys.py
@@ -14,9 +14,8 @@
# under the License.
from tempest.common.utils import data_utils
-from tempest.test import attr
-from tempest.test import skip_because
-from tempest.thirdparty.boto.test import BotoTestCase
+from tempest import test
+from tempest.thirdparty.boto import test as boto_test
def compare_key_pairs(a, b):
@@ -24,7 +23,7 @@
a.fingerprint == b.fingerprint)
-class EC2KeysTest(BotoTestCase):
+class EC2KeysTest(boto_test.BotoTestCase):
@classmethod
def setUpClass(cls):
@@ -33,7 +32,7 @@
cls.ec = cls.ec2_error_code
# TODO(afazekas): merge create, delete, get test cases
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_create_ec2_keypair(self):
# EC2 create KeyPair
key_name = data_utils.rand_name("keypair-")
@@ -42,16 +41,16 @@
self.assertTrue(compare_key_pairs(keypair,
self.client.get_key_pair(key_name)))
- @skip_because(bug="1072318")
- @attr(type='smoke')
+ @test.skip_because(bug="1072318")
+ @test.attr(type='smoke')
def test_delete_ec2_keypair(self):
# EC2 delete KeyPair
key_name = data_utils.rand_name("keypair-")
self.client.create_key_pair(key_name)
self.client.delete_key_pair(key_name)
- self.assertEqual(None, self.client.get_key_pair(key_name))
+ self.assertIsNone(self.client.get_key_pair(key_name))
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_get_ec2_keypair(self):
# EC2 get KeyPair
key_name = data_utils.rand_name("keypair-")
@@ -60,7 +59,7 @@
self.assertTrue(compare_key_pairs(keypair,
self.client.get_key_pair(key_name)))
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_duplicate_ec2_keypair(self):
# EC2 duplicate KeyPair
key_name = data_utils.rand_name("keypair-")
diff --git a/tempest/thirdparty/boto/test_ec2_network.py b/tempest/thirdparty/boto/test_ec2_network.py
index 4b2f01f..d508c07 100644
--- a/tempest/thirdparty/boto/test_ec2_network.py
+++ b/tempest/thirdparty/boto/test_ec2_network.py
@@ -13,12 +13,11 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.test import attr
-from tempest.test import skip_because
-from tempest.thirdparty.boto.test import BotoTestCase
+from tempest import test
+from tempest.thirdparty.boto import test as boto_test
-class EC2NetworkTest(BotoTestCase):
+class EC2NetworkTest(boto_test.BotoTestCase):
@classmethod
def setUpClass(cls):
@@ -26,8 +25,8 @@
cls.client = cls.os.ec2api_client
# Note(afazekas): these tests for things duable without an instance
- @skip_because(bug="1080406")
- @attr(type='smoke')
+ @test.skip_because(bug="1080406")
+ @test.attr(type='smoke')
def test_disassociate_not_associated_floating_ip(self):
# EC2 disassociate not associated floating ip
ec2_codes = self.ec2_error_code
diff --git a/tempest/thirdparty/boto/test_ec2_security_groups.py b/tempest/thirdparty/boto/test_ec2_security_groups.py
index 9b58603..86140ec 100644
--- a/tempest/thirdparty/boto/test_ec2_security_groups.py
+++ b/tempest/thirdparty/boto/test_ec2_security_groups.py
@@ -14,18 +14,18 @@
# under the License.
from tempest.common.utils import data_utils
-from tempest.test import attr
-from tempest.thirdparty.boto.test import BotoTestCase
+from tempest import test
+from tempest.thirdparty.boto import test as boto_test
-class EC2SecurityGroupTest(BotoTestCase):
+class EC2SecurityGroupTest(boto_test.BotoTestCase):
@classmethod
def setUpClass(cls):
super(EC2SecurityGroupTest, cls).setUpClass()
cls.client = cls.os.ec2api_client
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_create_authorize_security_group(self):
# EC2 Create, authorize/revoke security group
group_name = data_utils.rand_name("securty_group-")
diff --git a/tempest/thirdparty/boto/test_ec2_volumes.py b/tempest/thirdparty/boto/test_ec2_volumes.py
index 04671c5..6a771e5 100644
--- a/tempest/thirdparty/boto/test_ec2_volumes.py
+++ b/tempest/thirdparty/boto/test_ec2_volumes.py
@@ -13,10 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest import config
from tempest.openstack.common import log as logging
-from tempest.test import attr
-from tempest.thirdparty.boto.test import BotoTestCase
+from tempest import test
+from tempest.thirdparty.boto import test as boto_test
+CONF = config.CONF
LOG = logging.getLogger(__name__)
@@ -25,15 +27,20 @@
a.size == b.size)
-class EC2VolumesTest(BotoTestCase):
+class EC2VolumesTest(boto_test.BotoTestCase):
@classmethod
def setUpClass(cls):
super(EC2VolumesTest, cls).setUpClass()
+
+ if not CONF.service_available.cinder:
+ skip_msg = ("%s skipped as Cinder is not available" % cls.__name__)
+ raise cls.skipException(skip_msg)
+
cls.client = cls.os.ec2api_client
cls.zone = cls.client.get_good_zone()
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_create_get_delete(self):
# EC2 Create, get, delete Volume
volume = self.client.create_volume(1, self.zone)
@@ -46,7 +53,7 @@
self.client.delete_volume(volume.id)
self.cancelResourceCleanUp(cuk)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_create_volume_from_snapshot(self):
# EC2 Create volume from snapshot
volume = self.client.create_volume(1, self.zone)
diff --git a/tempest/thirdparty/boto/test_s3_buckets.py b/tempest/thirdparty/boto/test_s3_buckets.py
index f34faac..af6aa8b 100644
--- a/tempest/thirdparty/boto/test_s3_buckets.py
+++ b/tempest/thirdparty/boto/test_s3_buckets.py
@@ -14,20 +14,19 @@
# under the License.
from tempest.common.utils import data_utils
-from tempest.test import attr
-from tempest.test import skip_because
-from tempest.thirdparty.boto.test import BotoTestCase
+from tempest import test
+from tempest.thirdparty.boto import test as boto_test
-class S3BucketsTest(BotoTestCase):
+class S3BucketsTest(boto_test.BotoTestCase):
@classmethod
def setUpClass(cls):
super(S3BucketsTest, cls).setUpClass()
cls.client = cls.os.s3_client
- @skip_because(bug="1076965")
- @attr(type='smoke')
+ @test.skip_because(bug="1076965")
+ @test.attr(type='smoke')
def test_create_and_get_delete_bucket(self):
# S3 Create, get and delete bucket
bucket_name = data_utils.rand_name("s3bucket-")
diff --git a/tempest/thirdparty/boto/test_s3_ec2_images.py b/tempest/thirdparty/boto/test_s3_ec2_images.py
index 9607a92..d2300ee 100644
--- a/tempest/thirdparty/boto/test_s3_ec2_images.py
+++ b/tempest/thirdparty/boto/test_s3_ec2_images.py
@@ -17,14 +17,14 @@
from tempest.common.utils import data_utils
from tempest import config
-from tempest.test import attr
-from tempest.thirdparty.boto.test import BotoTestCase
-from tempest.thirdparty.boto.utils.s3 import s3_upload_dir
+from tempest import test
+from tempest.thirdparty.boto import test as boto_test
+from tempest.thirdparty.boto.utils import s3
CONF = config.CONF
-class S3ImagesTest(BotoTestCase):
+class S3ImagesTest(boto_test.BotoTestCase):
@classmethod
def setUpClass(cls):
@@ -46,9 +46,9 @@
cls.addResourceCleanUp(cls.destroy_bucket,
cls.s3_client.connection_data,
cls.bucket_name)
- s3_upload_dir(bucket, cls.materials_path)
+ s3.s3_upload_dir(bucket, cls.materials_path)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_register_get_deregister_ami_image(self):
# Register and deregister ami image
image = {"name": data_utils.rand_name("ami-name-"),
diff --git a/tempest/thirdparty/boto/test_s3_objects.py b/tempest/thirdparty/boto/test_s3_objects.py
index a102a22..1ae46de 100644
--- a/tempest/thirdparty/boto/test_s3_objects.py
+++ b/tempest/thirdparty/boto/test_s3_objects.py
@@ -18,18 +18,18 @@
import boto.s3.key
from tempest.common.utils import data_utils
-from tempest.test import attr
-from tempest.thirdparty.boto.test import BotoTestCase
+from tempest import test
+from tempest.thirdparty.boto import test as boto_test
-class S3BucketsTest(BotoTestCase):
+class S3BucketsTest(boto_test.BotoTestCase):
@classmethod
def setUpClass(cls):
super(S3BucketsTest, cls).setUpClass()
cls.client = cls.os.s3_client
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_create_get_delete_object(self):
# S3 Create, get and delete object
bucket_name = data_utils.rand_name("s3bucket-")
diff --git a/tempest/thirdparty/boto/utils/wait.py b/tempest/thirdparty/boto/utils/wait.py
index eed0a92..752ed0f 100644
--- a/tempest/thirdparty/boto/utils/wait.py
+++ b/tempest/thirdparty/boto/utils/wait.py
@@ -17,7 +17,7 @@
import time
import boto.exception
-from testtools import TestCase
+import testtools
from tempest import config
from tempest.openstack.common import log as logging
@@ -44,10 +44,11 @@
return status
dtime = time.time() - start_time
if dtime > CONF.boto.build_timeout:
- raise TestCase.failureException("State change timeout exceeded!"
- '(%ds) While waiting'
- 'for %s at "%s"' %
- (dtime, final_set, status))
+ raise testtools.TestCase\
+ .failureException("State change timeout exceeded!"
+ '(%ds) While waiting'
+ 'for %s at "%s"' %
+ (dtime, final_set, status))
time.sleep(CONF.boto.build_interval)
old_status = status
status = lfunction()
@@ -67,10 +68,11 @@
return result
dtime = time.time() - start_time
if dtime > CONF.boto.build_timeout:
- raise TestCase.failureException('Pattern find timeout exceeded!'
- '(%ds) While waiting for'
- '"%s" pattern in "%s"' %
- (dtime, regexp, text))
+ raise testtools.TestCase\
+ .failureException('Pattern find timeout exceeded!'
+ '(%ds) While waiting for'
+ '"%s" pattern in "%s"' %
+ (dtime, regexp, text))
time.sleep(CONF.boto.build_interval)
@@ -98,8 +100,8 @@
# Let the other exceptions propagate
dtime = time.time() - start_time
if dtime > CONF.boto.build_timeout:
- raise TestCase.failureException("Wait timeout exceeded! (%ds)" %
- dtime)
+ raise testtools.TestCase\
+ .failureException("Wait timeout exceeded! (%ds)" % dtime)
time.sleep(CONF.boto.build_interval)
@@ -116,8 +118,8 @@
return exc
dtime = time.time() - start_time
if dtime > CONF.boto.build_timeout:
- raise TestCase.failureException("Wait timeout exceeded! (%ds)" %
- dtime)
+ raise testtools.TestCase\
+ .failureException("Wait timeout exceeded! (%ds)" % dtime)
time.sleep(CONF.boto.build_interval)
# TODO(afazekas): consider strategy design pattern..
diff --git a/tools/check_logs.py b/tools/check_logs.py
index 15988a6..98e079a 100755
--- a/tools/check_logs.py
+++ b/tools/check_logs.py
@@ -32,7 +32,7 @@
def process_files(file_specs, url_specs, whitelists):
- regexp = re.compile(r"^.* (ERROR|CRITICAL) .*\[.*\-.*\]")
+ regexp = re.compile(r"^.* (ERROR|CRITICAL|TRACE) .*\[.*\-.*\]")
had_errors = False
for (name, filename) in file_specs:
whitelist = whitelists.get(name, [])
diff --git a/tox.ini b/tox.ini
index 1580b14..4a625f8 100644
--- a/tox.ini
+++ b/tox.ini
@@ -4,11 +4,10 @@
skipsdist = True
[testenv]
-sitepackages = True
setenv = VIRTUAL_ENV={envdir}
OS_TEST_PATH=./tempest/test_discover
usedevelop = True
-install_command = pip install {opts} {packages}
+install_command = pip install -U {opts} {packages}
[testenv:py26]
setenv = OS_TEST_PATH=./tempest/tests
@@ -27,11 +26,13 @@
commands = python setup.py testr --coverage --testr-arg='tempest\.tests {posargs}'
[testenv:all]
+sitepackages = True
setenv = VIRTUAL_ENV={envdir}
commands =
- python setup.py testr --slowest --testr-args='{posargs}'
+ bash tools/pretty_tox.sh '{posargs}'
[testenv:full]
+sitepackages = True
# The regex below is used to select which tests to run and exclude the slow tag:
# See the testrepostiory bug: https://bugs.launchpad.net/testrepository/+bug/1208610
commands =
@@ -44,49 +45,29 @@
bash tools/pretty_tox_serial.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli)) {posargs}'
[testenv:testr-full]
+sitepackages = True
commands =
bash tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli)) {posargs}'
[testenv:heat-slow]
+sitepackages = True
setenv = OS_TEST_TIMEOUT=1200
# The regex below is used to select heat api/scenario tests tagged as slow.
commands =
bash tools/pretty_tox_serial.sh '(?=.*\[.*\bslow\b.*\])(^tempest\.(api|scenario)\.orchestration) {posargs}'
[testenv:large-ops]
+sitepackages = True
commands =
python setup.py testr --slowest --testr-args='tempest.scenario.test_large_ops {posargs}'
-
-[testenv:py26-full]
-setenv = VIRTUAL_ENV={envdir}
- NOSE_WITH_OPENSTACK=1
- NOSE_OPENSTACK_COLOR=1
- NOSE_OPENSTACK_RED=15
- NOSE_OPENSTACK_YELLOW=3
- NOSE_OPENSTACK_SHOW_ELAPSED=1
- NOSE_OPENSTACK_STDOUT=1
- TEMPEST_PY26_NOSE_COMPAT=1
-commands =
- nosetests --logging-format '%(asctime)-15s %(message)s' --with-xunit -sv --xunit-file=nosetests-full.xml tempest/api tempest/scenario tempest/thirdparty tempest/cli {posargs}
-
-[testenv:py26-smoke]
-setenv = VIRTUAL_ENV={envdir}
-NOSE_WITH_OPENSTACK=1
- NOSE_OPENSTACK_COLOR=1
- NOSE_OPENSTACK_RED=15
- NOSE_OPENSTACK_YELLOW=3
- NOSE_OPENSTACK_SHOW_ELAPSED=1
- NOSE_OPENSTACK_STDOUT=1
- TEMPEST_PY26_NOSE_COMPAT=1
-commands =
- nosetests --logging-format '%(asctime)-15s %(message)s' --with-xunit -sv --attr=type=smoke --xunit-file=nosetests-smoke.xml tempest {posargs}
-
[testenv:smoke]
+sitepackages = True
commands =
bash tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])((smoke)|(^tempest\.scenario)) {posargs}'
[testenv:smoke-serial]
+sitepackages = True
# This is still serial because neutron doesn't work with parallel. See:
# https://bugs.launchpad.net/tempest/+bug/1216076 so the neutron smoke
# job would fail if we moved it to parallel.
@@ -94,6 +75,7 @@
bash tools/pretty_tox_serial.sh '(?!.*\[.*\bslow\b.*\])((smoke)|(^tempest\.scenario)) {posargs}'
[testenv:stress]
+sitepackages = True
commands =
python -m tempest/stress/run_stress -a -d 3600 -S