Merge "Adds "user-password-update" to v3/test_users"
diff --git a/tempest/api/compute/admin/test_servers_negative.py b/tempest/api/compute/admin/test_servers_negative.py
index cccaf13..f4d010e 100644
--- a/tempest/api/compute/admin/test_servers_negative.py
+++ b/tempest/api/compute/admin/test_servers_negative.py
@@ -127,6 +127,8 @@
                           self.client.migrate_server,
                           str(uuid.uuid4()))
 
+    @testtools.skipUnless(CONF.compute_feature_enabled.resize,
+                          'Resize not available.')
     @testtools.skipUnless(CONF.compute_feature_enabled.suspend,
                           'Suspend is not available.')
     @test.attr(type=['negative', 'gate'])
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index f66020c..9d39c9f 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -203,11 +203,13 @@
         params = {'status': 'active'}
         resp, body = self.client.list_servers_with_detail(params)
         servers = body['servers']
+        test_ids = [s['id'] for s in (self.s1, self.s2, self.s3)]
 
         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])
+        self.assertEqual(['ACTIVE'] * 3, [x['status'] for x in servers
+                                          if x['id'] in test_ids])
 
     @test.attr(type='gate')
     def test_list_servers_filtered_by_name_wildcard(self):
diff --git a/tempest/api/network/admin/test_quotas.py b/tempest/api/network/admin/test_quotas.py
index d1a8faf..9fa54b1 100644
--- a/tempest/api/network/admin/test_quotas.py
+++ b/tempest/api/network/admin/test_quotas.py
@@ -46,8 +46,7 @@
             raise cls.skipException(msg)
         cls.identity_admin_client = cls.os_adm.identity_client
 
-    @test.attr(type='gate')
-    def test_quotas(self):
+    def _check_quotas(self, new_quotas):
         # Add a tenant to conduct the test
         test_tenant = data_utils.rand_name('test_tenant_')
         test_description = data_utils.rand_name('desc_')
@@ -56,14 +55,15 @@
             description=test_description)
         tenant_id = tenant['id']
         self.addCleanup(self.identity_admin_client.delete_tenant, tenant_id)
+
         # Change quotas for tenant
-        new_quotas = {'network': 0, 'security_group': 0}
         resp, quota_set = self.admin_client.update_quotas(tenant_id,
                                                           **new_quotas)
         self.assertEqual('200', resp['status'])
         self.addCleanup(self.admin_client.reset_quotas, tenant_id)
-        self.assertEqual(0, quota_set['network'])
-        self.assertEqual(0, quota_set['security_group'])
+        for key, value in new_quotas.iteritems():
+            self.assertEqual(value, quota_set[key])
+
         # Confirm our tenant is listed among tenants with non default quotas
         resp, non_default_quotas = self.admin_client.list_quotas()
         self.assertEqual('200', resp['status'])
@@ -72,12 +72,14 @@
             if qs['tenant_id'] == tenant_id:
                 found = True
         self.assertTrue(found)
-        # Confirm from APi quotas were changed as requested for tenant
+
+        # Confirm from API quotas were changed as requested for tenant
         resp, quota_set = self.admin_client.show_quotas(tenant_id)
         quota_set = quota_set['quota']
         self.assertEqual('200', resp['status'])
-        self.assertEqual(0, quota_set['network'])
-        self.assertEqual(0, quota_set['security_group'])
+        for key, value in new_quotas.iteritems():
+            self.assertEqual(value, quota_set[key])
+
         # Reset quotas to default and confirm
         resp, body = self.admin_client.reset_quotas(tenant_id)
         self.assertEqual('204', resp['status'])
@@ -86,49 +88,14 @@
         for q in non_default_quotas['quotas']:
             self.assertNotEqual(tenant_id, q['tenant_id'])
 
+    @test.attr(type='gate')
+    def test_quotas(self):
+        new_quotas = {'network': 0, 'security_group': 0}
+        self._check_quotas(new_quotas)
+
     @test.requires_ext(extension='lbaas', service='network')
     @test.attr(type='gate')
     def test_lbaas_quotas(self):
-        # Add a tenant to conduct the test
-        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)
-        # Change lbaas quotas for tenant
         new_quotas = {'vip': 1, 'pool': 2,
                       'member': 3, 'health_monitor': 4}
-
-        resp, quota_set = self.admin_client.update_quotas(tenant_id,
-                                                          **new_quotas)
-        self.assertEqual('200', resp['status'])
-        self.addCleanup(self.admin_client.reset_quotas, tenant_id)
-        self.assertEqual(1, quota_set['vip'])
-        self.assertEqual(2, quota_set['pool'])
-        self.assertEqual(3, quota_set['member'])
-        self.assertEqual(4, quota_set['health_monitor'])
-        # Confirm our tenant is listed among tenants with non default quotas
-        resp, non_default_quotas = self.admin_client.list_quotas()
-        self.assertEqual('200', resp['status'])
-        found = False
-        for qs in non_default_quotas['quotas']:
-            if qs['tenant_id'] == tenant_id:
-                found = True
-        self.assertTrue(found)
-        # Confirm from APi quotas were changed as requested for tenant
-        resp, quota_set = self.admin_client.show_quotas(tenant_id)
-        quota_set = quota_set['quota']
-        self.assertEqual('200', resp['status'])
-        self.assertEqual(1, quota_set['vip'])
-        self.assertEqual(2, quota_set['pool'])
-        self.assertEqual(3, quota_set['member'])
-        self.assertEqual(4, quota_set['health_monitor'])
-        # Reset quotas to default and confirm
-        resp, body = self.admin_client.reset_quotas(tenant_id)
-        self.assertEqual('204', resp['status'])
-        resp, non_default_quotas = self.admin_client.list_quotas()
-        self.assertEqual('200', resp['status'])
-        for q in non_default_quotas['quotas']:
-            self.assertNotEqual(tenant_id, q['tenant_id'])
+        self._check_quotas(new_quotas)
diff --git a/tempest/api/orchestration/base.py b/tempest/api/orchestration/base.py
index f83169f..531df2d 100644
--- a/tempest/api/orchestration/base.py
+++ b/tempest/api/orchestration/base.py
@@ -85,11 +85,8 @@
                 pass
 
         for stack_identifier in cls.stacks:
-            try:
-                cls.client.wait_for_stack_status(
-                    stack_identifier, 'DELETE_COMPLETE')
-            except exceptions.NotFound:
-                pass
+            cls.client.wait_for_stack_status(
+                stack_identifier, 'DELETE_COMPLETE')
 
     @classmethod
     def _create_keypair(cls, name_start='keypair-heat-'):
diff --git a/tempest/api/telemetry/test_telemetry_notification_api.py b/tempest/api/telemetry/test_telemetry_notification_api.py
index 148f5a3..f401b9b 100644
--- a/tempest/api/telemetry/test_telemetry_notification_api.py
+++ b/tempest/api/telemetry/test_telemetry_notification_api.py
@@ -32,6 +32,7 @@
     @test.attr(type="gate")
     @testtools.skipIf(not CONF.service_available.nova,
                       "Nova is not available.")
+    @test.skip_because(bug="1336755")
     def test_check_nova_notification(self):
 
         resp, body = self.create_server()
diff --git a/tempest/cmd/javelin.py b/tempest/cmd/javelin.py
index 96bbd03..c1a2e46 100755
--- a/tempest/cmd/javelin.py
+++ b/tempest/cmd/javelin.py
@@ -244,9 +244,13 @@
             r, found = client.servers.get_server(found['id'])
             # get the ipv4 address
             addr = found['addresses']['private'][0]['addr']
-            self.assertEqual(os.system("ping -c 1 " + addr), 0,
-                             "Server %s is not pingable at %s" % (
-                                 server['name'], addr))
+            for count in range(60):
+                return_code = os.system("ping -c1 " + addr)
+                if return_code is 0:
+                    break
+            self.assertNotEqual(count, 59,
+                               "Server %s is not pingable at %s" % (
+                               server['name'], addr))
 
     def check_volumes(self):
         """Check that the volumes are still there and attached."""
@@ -308,6 +312,7 @@
 def create_images(images):
     if not images:
         return
+    LOG.info("Creating images")
     for image in images:
         client = client_for_user(image['owner'])
 
@@ -315,6 +320,7 @@
         r, body = client.images.image_list()
         names = [x['name'] for x in body]
         if image['name'] in names:
+            LOG.info("Image '%s' already exists" % image['name'])
             continue
 
         # special handling for 3 part image
@@ -372,15 +378,37 @@
 def create_servers(servers):
     if not servers:
         return
+    LOG.info("Creating servers")
     for server in servers:
         client = client_for_user(server['owner'])
 
         if _get_server_by_name(client, server['name']):
+            LOG.info("Server '%s' already exists" % server['name'])
             continue
 
         image_id = _get_image_by_name(client, server['image'])['id']
         flavor_id = _get_flavor_by_name(client, server['flavor'])['id']
-        client.servers.create_server(server['name'], image_id, flavor_id)
+        resp, body = client.servers.create_server(server['name'], image_id,
+                                                 flavor_id)
+        server_id = body['id']
+        client.servers.wait_for_server_status(server_id, 'ACTIVE')
+
+
+def destroy_servers(servers):
+    if not servers:
+        return
+    LOG.info("Destroying servers")
+    for server in servers:
+        client = client_for_user(server['owner'])
+
+        response = _get_server_by_name(client, server['name'])
+        if not response:
+            LOG.info("Server '%s' does not exist" % server['name'])
+            continue
+
+        client.servers.delete_server(response['id'])
+        client.servers.wait_for_server_termination(response['id'],
+                ignore_error=True)
 
 
 #######################
@@ -441,6 +469,23 @@
     # attach_volumes(RES['volumes'])
 
 
+def destroy_resources():
+    LOG.info("Destroying Resources")
+    # Destroy in inverse order of create
+
+    # Future
+    # detach_volumes
+    # destroy_volumes
+
+    destroy_servers(RES['servers'])
+    LOG.warn("Destroy mode incomplete")
+    # destroy_images
+    # destroy_objects
+
+    # destroy_users
+    # destroy_tenants
+
+
 def get_options():
     global OPTS
     parser = argparse.ArgumentParser(
@@ -512,12 +557,16 @@
 
     if OPTS.mode == 'create':
         create_resources()
+        # Make sure the resources we just created actually work
+        checker = JavelinCheck(USERS, RES)
+        checker.check()
     elif OPTS.mode == 'check':
         collect_users(RES['users'])
         checker = JavelinCheck(USERS, RES)
         checker.check()
     elif OPTS.mode == 'destroy':
-        LOG.warn("Destroy mode not yet implemented")
+        collect_users(RES['users'])
+        destroy_resources()
     else:
         LOG.error('Unknown mode %s' % OPTS.mode)
         return 1
diff --git a/tempest/common/cred_provider.py b/tempest/common/cred_provider.py
new file mode 100644
index 0000000..dc4f049
--- /dev/null
+++ b/tempest/common/cred_provider.py
@@ -0,0 +1,44 @@
+# (c) 2014 Deutsche Telekom AG
+#    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 abc
+import six
+
+from tempest import config
+from tempest.openstack.common import log as logging
+
+CONF = config.CONF
+LOG = logging.getLogger(__name__)
+
+
+@six.add_metaclass(abc.ABCMeta)
+class CredentialProvider(object):
+    def __init__(self, name, tempest_client=True, interface='json',
+                 password='pass', network_resources=None):
+        self.name = name
+
+    @abc.abstractmethod
+    def get_primary_creds(self):
+        return
+
+    @abc.abstractmethod
+    def get_admin_creds(self):
+        return
+
+    @abc.abstractmethod
+    def get_alt_creds(self):
+        return
+
+    @abc.abstractmethod
+    def clear_isolated_creds(self):
+        return
diff --git a/tempest/common/isolated_creds.py b/tempest/common/isolated_creds.py
index 208f42f..98b0116 100644
--- a/tempest/common/isolated_creds.py
+++ b/tempest/common/isolated_creds.py
@@ -16,6 +16,7 @@
 
 from tempest import auth
 from tempest import clients
+from tempest.common import cred_provider
 from tempest.common.utils import data_utils
 from tempest import config
 from tempest import exceptions
@@ -25,15 +26,16 @@
 LOG = logging.getLogger(__name__)
 
 
-class IsolatedCreds(object):
+class IsolatedCreds(cred_provider.CredentialProvider):
 
     def __init__(self, name, tempest_client=True, interface='json',
                  password='pass', network_resources=None):
+        super(IsolatedCreds, self).__init__(name, tempest_client, interface,
+                                            password, network_resources)
         self.network_resources = network_resources
         self.isolated_creds = {}
         self.isolated_net_resources = {}
         self.ports = []
-        self.name = name
         self.tempest_client = tempest_client
         self.interface = interface
         self.password = password
diff --git a/tempest/scenario/test_dashboard_basic_ops.py b/tempest/scenario/test_dashboard_basic_ops.py
index 6418a73..4fcc70a 100644
--- a/tempest/scenario/test_dashboard_basic_ops.py
+++ b/tempest/scenario/test_dashboard_basic_ops.py
@@ -24,7 +24,7 @@
 CONF = config.CONF
 
 
-class TestDashboardBasicOps(manager.OfficialClientTest):
+class TestDashboardBasicOps(manager.ScenarioTest):
 
     """
     This is a basic scenario test:
diff --git a/tempest/services/orchestration/json/orchestration_client.py b/tempest/services/orchestration/json/orchestration_client.py
index d325eb5..46b0ec4 100644
--- a/tempest/services/orchestration/json/orchestration_client.py
+++ b/tempest/services/orchestration/json/orchestration_client.py
@@ -181,7 +181,11 @@
         fail_regexp = re.compile(failure_pattern)
 
         while True:
-            resp, body = self.get_stack(stack_identifier)
+            try:
+                resp, body = self.get_stack(stack_identifier)
+            except exceptions.NotFound:
+                if status == 'DELETE_COMPLETE':
+                    return
             stack_name = body['stack_name']
             stack_status = body['stack_status']
             if stack_status == status: