Merge "Fix exception name in test_server_actions"
diff --git a/tempest/services/compute/json/security_groups_client.py b/tempest/services/compute/json/security_groups_client.py
index 95f2831..7f430d8 100644
--- a/tempest/services/compute/json/security_groups_client.py
+++ b/tempest/services/compute/json/security_groups_client.py
@@ -95,3 +95,12 @@
def delete_security_group_rule(self, group_rule_id):
"""Deletes the provided Security Group rule."""
return self.delete('os-security-group-rules/%s' % str(group_rule_id))
+
+ def list_security_group_rules(self, security_group_id):
+ """List all rules for a security group."""
+ resp, body = self.get('os-security-groups')
+ body = json.loads(body)
+ for sg in body['security_groups']:
+ if sg['id'] == security_group_id:
+ return resp, sg['rules']
+ raise exceptions.NotFound('No such Security Group')
diff --git a/tempest/services/compute/xml/security_groups_client.py b/tempest/services/compute/xml/security_groups_client.py
index ac70f1b..7db60a1 100644
--- a/tempest/services/compute/xml/security_groups_client.py
+++ b/tempest/services/compute/xml/security_groups_client.py
@@ -23,6 +23,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
class SecurityGroupsClientXML(RestClientXML):
@@ -128,3 +129,16 @@
"""Deletes the provided Security Group rule."""
return self.delete('os-security-group-rules/%s' %
str(group_rule_id), self.headers)
+
+ def list_security_group_rules(self, security_group_id):
+ """List all rules for a security group."""
+ url = "os-security-groups"
+ resp, body = self.get(url, self.headers)
+ body = etree.fromstring(body)
+ secgroups = body.getchildren()
+ for secgroup in secgroups:
+ if secgroup.get('id') == security_group_id:
+ node = secgroup.find('{%s}rules' % XMLNS_11)
+ rules = [xml_to_json(x) for x in node.getchildren()]
+ return resp, rules
+ raise exceptions.NotFound('No such Security Group')
diff --git a/tempest/services/compute/xml/servers_client.py b/tempest/services/compute/xml/servers_client.py
index 655a345..fceeb28 100644
--- a/tempest/services/compute/xml/servers_client.py
+++ b/tempest/services/compute/xml/servers_client.py
@@ -160,7 +160,7 @@
return array
def list_servers(self, params=None):
- url = 'servers/detail'
+ url = 'servers'
if params:
url += '?%s' % urllib.urlencode(params)
diff --git a/tempest/tests/compute/security_groups/test_security_group_rules.py b/tempest/tests/compute/security_groups/test_security_group_rules.py
index dc85f4b..99d9a5d 100644
--- a/tempest/tests/compute/security_groups/test_security_group_rules.py
+++ b/tempest/tests/compute/security_groups/test_security_group_rules.py
@@ -232,6 +232,49 @@
self.client.delete_security_group_rule,
rand_name('999'))
+ @attr(type='positive')
+ def test_security_group_rules_list(self):
+ # Positive test: Created Security Group rules should be
+ # in the list of all rules
+ # Creating a Security Group to add rules to it
+ s_name = rand_name('securitygroup-')
+ s_description = rand_name('description-')
+ resp, securitygroup = \
+ self.client.create_security_group(s_name, s_description)
+ securitygroup_id = securitygroup['id']
+ # Delete the Security Group at the end of this method
+ self.addCleanup(self.client.delete_security_group, securitygroup_id)
+
+ # Add a first rule to the created Security Group
+ ip_protocol1 = 'tcp'
+ from_port1 = 22
+ to_port1 = 22
+ resp, rule = \
+ self.client.create_security_group_rule(securitygroup_id,
+ ip_protocol1,
+ from_port1, to_port1)
+ rule1_id = rule['id']
+ # Delete the Security Group rule1 at the end of this method
+ self.addCleanup(self.client.delete_security_group_rule, rule1_id)
+
+ # Add a second rule to the created Security Group
+ ip_protocol2 = 'icmp'
+ from_port2 = -1
+ to_port2 = -1
+ resp, rule = \
+ self.client.create_security_group_rule(securitygroup_id,
+ ip_protocol2,
+ from_port2, to_port2)
+ rule2_id = rule['id']
+ # Delete the Security Group rule2 at the end of this method
+ self.addCleanup(self.client.delete_security_group_rule, rule2_id)
+
+ # Get rules of the created Security Group
+ resp, rules = \
+ self.client.list_security_group_rules(securitygroup_id)
+ self.assertTrue(any([i for i in rules if i['id'] == rule1_id]))
+ self.assertTrue(any([i for i in rules if i['id'] == rule2_id]))
+
class SecurityGroupRulesTestXML(SecurityGroupRulesTestJSON):
_interface = 'xml'
diff --git a/tempest/tests/compute/servers/test_list_server_filters.py b/tempest/tests/compute/servers/test_list_server_filters.py
index 897ca34..ff599fe 100644
--- a/tempest/tests/compute/servers/test_list_server_filters.py
+++ b/tempest/tests/compute/servers/test_list_server_filters.py
@@ -73,12 +73,6 @@
cls.client.wait_for_server_status(cls.s3['id'], 'ACTIVE')
resp, cls.s3 = cls.client.get_server(cls.s3['id'])
- # The list server call returns minimal results, so we need
- # a less detailed version of each server also
- cls.s1_min = cls._convert_to_min_details(cls.s1)
- cls.s2_min = cls._convert_to_min_details(cls.s2)
- cls.s3_min = cls._convert_to_min_details(cls.s3)
-
@classmethod
def tearDownClass(cls):
cls.client.delete_server(cls.s1['id'])
@@ -86,10 +80,6 @@
cls.client.delete_server(cls.s3['id'])
super(ListServerFiltersTestJSON, cls).tearDownClass()
- def _server_id_in_results(self, server_id, results):
- ids = [row['id'] for row in results]
- return server_id in ids
-
@utils.skip_unless_attr('multiple_images', 'Only one image found')
@attr(type='positive')
def test_list_servers_filter_by_image(self):
@@ -98,9 +88,9 @@
resp, body = self.client.list_servers(params)
servers = body['servers']
- self.assertTrue(self._server_id_in_results(self.s1['id'], servers))
- self.assertFalse(self._server_id_in_results(self.s2['id'], servers))
- self.assertTrue(self._server_id_in_results(self.s3['id'], servers))
+ self.assertIn(self.s1['id'], map(lambda x: x['id'], servers))
+ self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers))
+ self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
@attr(type='positive')
def test_list_servers_filter_by_flavor(self):
@@ -109,9 +99,9 @@
resp, body = self.client.list_servers(params)
servers = body['servers']
- self.assertFalse(self._server_id_in_results(self.s1['id'], servers))
- self.assertFalse(self._server_id_in_results(self.s2['id'], servers))
- self.assertTrue(self._server_id_in_results(self.s3['id'], servers))
+ self.assertNotIn(self.s1['id'], map(lambda x: x['id'], servers))
+ self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers))
+ self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
@attr(type='positive')
def test_list_servers_filter_by_server_name(self):
@@ -120,9 +110,9 @@
resp, body = self.client.list_servers(params)
servers = body['servers']
- self.assertTrue(self._server_id_in_results(self.s1['id'], servers))
- self.assertFalse(self._server_id_in_results(self.s2['id'], servers))
- self.assertFalse(self._server_id_in_results(self.s3['id'], servers))
+ self.assertIn(self.s1_name, map(lambda x: x['name'], servers))
+ self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers))
+ self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers))
@attr(type='positive')
def test_list_servers_filter_by_server_status(self):
@@ -131,12 +121,12 @@
resp, body = self.client.list_servers(params)
servers = body['servers']
- self.assertTrue(self._server_id_in_results(self.s1['id'], servers))
- self.assertTrue(self._server_id_in_results(self.s2['id'], servers))
- self.assertTrue(self._server_id_in_results(self.s3['id'], servers))
+ self.assertIn(self.s1['id'], map(lambda x: x['id'], servers))
+ self.assertIn(self.s2['id'], map(lambda x: x['id'], servers))
+ self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
@attr(type='positive')
- def test_list_servers_limit_results(self):
+ def test_list_servers_detailed_filter_by_limit(self):
# Verify only the expected number of servers are returned
params = {'limit': 1}
resp, servers = self.client.list_servers_with_detail(params)
@@ -150,9 +140,9 @@
resp, body = self.client.list_servers_with_detail(params)
servers = body['servers']
- self.assertTrue(self._server_id_in_results(self.s1['id'], servers))
- self.assertFalse(self._server_id_in_results(self.s2['id'], servers))
- self.assertTrue(self._server_id_in_results(self.s3['id'], servers))
+ self.assertIn(self.s1['id'], map(lambda x: x['id'], servers))
+ self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers))
+ self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
@attr(type='positive')
def test_list_servers_detailed_filter_by_flavor(self):
@@ -161,9 +151,9 @@
resp, body = self.client.list_servers_with_detail(params)
servers = body['servers']
- self.assertFalse(self._server_id_in_results(self.s1['id'], servers))
- self.assertFalse(self._server_id_in_results(self.s2['id'], servers))
- self.assertTrue(self._server_id_in_results(self.s3['id'], servers))
+ self.assertNotIn(self.s1['id'], map(lambda x: x['id'], servers))
+ self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers))
+ self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
@attr(type='positive')
def test_list_servers_detailed_filter_by_server_name(self):
@@ -172,9 +162,9 @@
resp, body = self.client.list_servers_with_detail(params)
servers = body['servers']
- self.assertTrue(self._server_id_in_results(self.s1['id'], servers))
- self.assertFalse(self._server_id_in_results(self.s2['id'], servers))
- self.assertFalse(self._server_id_in_results(self.s3['id'], servers))
+ self.assertIn(self.s1_name, map(lambda x: x['name'], servers))
+ self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers))
+ self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers))
@attr(type='positive')
def test_list_servers_detailed_filter_by_server_status(self):
@@ -183,9 +173,10 @@
resp, body = self.client.list_servers_with_detail(params)
servers = body['servers']
- self.assertTrue(self._server_id_in_results(self.s1['id'], servers))
- self.assertTrue(self._server_id_in_results(self.s2['id'], servers))
- self.assertTrue(self._server_id_in_results(self.s3['id'], servers))
+ self.assertIn(self.s1['id'], map(lambda x: x['id'], servers))
+ self.assertIn(self.s2['id'], map(lambda x: x['id'], servers))
+ self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
+ self.assertEqual(['ACTIVE'] * 3, [x['status'] for x in servers])
@attr(type='positive')
def test_list_servers_detailed_limit_results(self):
@@ -194,14 +185,6 @@
resp, servers = self.client.list_servers_with_detail(params)
self.assertEqual(1, len(servers['servers']))
- @classmethod
- def _convert_to_min_details(self, server):
- min_detail = {}
- min_detail['name'] = server['name']
- min_detail['links'] = server['links']
- min_detail['id'] = server['id']
- return min_detail
-
class ListServerFiltersTestXML(ListServerFiltersTestJSON):
_interface = 'xml'
diff --git a/tempest/tests/compute/test_authorization.py b/tempest/tests/compute/test_authorization.py
index 52e457d..7bd5c75 100644
--- a/tempest/tests/compute/test_authorization.py
+++ b/tempest/tests/compute/test_authorization.py
@@ -316,15 +316,11 @@
# A get metadata for another user's server should fail
req_metadata = {'meta1': 'data1'}
self.client.set_server_metadata(self.server['id'], req_metadata)
- try:
- resp, meta = \
- self.alt_client.get_server_metadata_item(self.server['id'],
- 'meta1')
- except exceptions.NotFound:
- pass
- finally:
- resp, body = \
- self.client.delete_server_metadata_item(self.server['id'], 'meta1')
+ self.addCleanup(self.client.delete_server_metadata_item,
+ self.server['id'], 'meta1')
+ self.assertRaises(exceptions.NotFound,
+ self.alt_client.get_server_metadata_item,
+ self.server['id'], 'meta1')
def test_get_metadata_of_alt_account_image_fails(self):
# A get metadata for another user's image should fail
diff --git a/tools/find_stack_traces.py b/tools/find_stack_traces.py
new file mode 100755
index 0000000..e6c1990
--- /dev/null
+++ b/tools/find_stack_traces.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# 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.
+
+import gzip
+import re
+import StringIO
+import sys
+import urllib2
+
+
+def hunt_for_stacktrace(url):
+ """Return TRACE or ERROR lines out of logs."""
+ page = urllib2.urlopen(url)
+ buf = StringIO.StringIO(page.read())
+ f = gzip.GzipFile(fileobj=buf)
+ content = f.read()
+ traces = re.findall('^(.*? (TRACE|ERROR) .*?)$', content, re.MULTILINE)
+ tracelist = map(lambda x: x[0], traces)
+ # filter out log definitions as false possitives
+ return filter(lambda x: not re.search('logging_exception_prefix', x),
+ tracelist)
+
+
+def log_url(url, log):
+ return "%s/%s" % (url, log)
+
+
+def collect_logs(url):
+ page = urllib2.urlopen(url)
+ content = page.read()
+ logs = re.findall('(screen-[\w-]+\.txt\.gz)</a>', content)
+ return logs
+
+
+def usage():
+ print """
+Usage: find_stack_traces.py <logurl>
+
+Hunts for stack traces in a devstack run. Must provide it a base log url
+from a tempest devstack run. Should start with http and end with /logs/.
+
+Returns a report listing stack traces out of the various files where
+they are found.
+"""
+ sys.exit(0)
+
+
+def main():
+ if len(sys.argv) == 2:
+ url = sys.argv[1]
+ loglist = collect_logs(url)
+
+ # probably wrong base url
+ if not loglist:
+ usage()
+
+ for log in loglist:
+ logurl = log_url(url, log)
+ traces = hunt_for_stacktrace(logurl)
+ if traces:
+ print "\n\nTRACES found in %s\n" % log
+ for line in traces:
+ print line
+ else:
+ usage()
+
+if __name__ == '__main__':
+ main()
diff --git a/tools/pip-requires b/tools/pip-requires
index ee21065..e85cced 100644
--- a/tools/pip-requires
+++ b/tools/pip-requires
@@ -13,5 +13,4 @@
testresources
keyring
testrepository
-
-http://tarballs.openstack.org/oslo-config/oslo.config-1.1.0b1.tar.gz#egg=oslo.config
+oslo.config>=1.1.0
diff --git a/tools/skip_tracker.py b/tools/skip_tracker.py
index e890e92..12d29b0 100755
--- a/tools/skip_tracker.py
+++ b/tools/skip_tracker.py
@@ -89,6 +89,7 @@
results = find_skips()
unique_bugs = sorted(set([bug for (method, bug) in results]))
unskips = []
+ duplicates = []
info("Total bug skips found: %d", len(results))
info("Total unique bugs causing skips: %d", len(unique_bugs))
lp = launchpad.Launchpad.login_anonymously('grabbing bugs',
@@ -96,12 +97,26 @@
LPCACHEDIR)
for bug_no in unique_bugs:
bug = lp.bugs[bug_no]
+ duplicate = bug.duplicate_of_link
+ if duplicate is not None:
+ dup_id = duplicate.split('/')[-1]
+ duplicates.append((bug_no, dup_id))
for task in bug.bug_tasks:
info("Bug #%7s (%12s - %12s)", bug_no,
task.importance, task.status)
if task.status in ('Fix Released', 'Fix Committed'):
unskips.append(bug_no)
+ for bug_id, dup_id in duplicates:
+ if bug_id not in unskips:
+ dup_bug = lp.bugs[dup_id]
+ for task in dup_bug.bug_tasks:
+ info("Bug #%7s is a duplicate of Bug#%7s (%12s - %12s)",
+ bug_id, dup_id, task.importance, task.status)
+ if task.status in ('Fix Released', 'Fix Committed'):
+ unskips.append(bug_id)
+
+ unskips = sorted(set(unskips))
if unskips:
print "The following bugs have been fixed and the corresponding skips"
print "should be removed from the test cases:"