Merge "Add slow tag for test_ceilometer_resource_list"
diff --git a/tempest/api/identity/admin/v3/test_endpoints.py b/tempest/api/identity/admin/v3/test_endpoints.py
index 05b704f..0e4d66b 100644
--- a/tempest/api/identity/admin/v3/test_endpoints.py
+++ b/tempest/api/identity/admin/v3/test_endpoints.py
@@ -102,6 +102,7 @@
             self.client.create_endpoint(self.service_id, interface1,
                                         url1, region=region1,
                                         enabled=True)
+        self.addCleanup(self.client.delete_endpoint, endpoint_for_update['id'])
         # Creating service so as update endpoint with new service ID
         s_name = data_utils.rand_name('service-')
         s_type = data_utils.rand_name('type--')
@@ -126,7 +127,6 @@
         self.assertEqual(url2, endpoint['url'])
         self.assertEqual(region2, endpoint['region'])
         self.assertEqual('false', str(endpoint['enabled']).lower())
-        self.addCleanup(self.client.delete_endpoint, endpoint_for_update['id'])
 
 
 class EndPointsTestXML(EndPointsTestJSON):
diff --git a/tempest/api/identity/admin/v3/test_endpoints_negative.py b/tempest/api/identity/admin/v3/test_endpoints_negative.py
new file mode 100644
index 0000000..28615a4
--- /dev/null
+++ b/tempest/api/identity/admin/v3/test_endpoints_negative.py
@@ -0,0 +1,94 @@
+
+# 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.identity import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest.test import attr
+
+
+class EndpointsNegativeTestJSON(base.BaseIdentityV3AdminTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(EndpointsNegativeTestJSON, cls).setUpClass()
+        cls.identity_client = cls.client
+        cls.client = cls.endpoints_client
+        cls.service_ids = list()
+        s_name = data_utils.rand_name('service-')
+        s_type = data_utils.rand_name('type--')
+        s_description = data_utils.rand_name('description-')
+        resp, cls.service_data = (
+            cls.service_client.create_service(s_name, s_type,
+                                              description=s_description))
+        cls.service_id = cls.service_data['id']
+        cls.service_ids.append(cls.service_id)
+
+    @classmethod
+    def tearDownClass(cls):
+        for s in cls.service_ids:
+            cls.service_client.delete_service(s)
+        super(EndpointsNegativeTestJSON, cls).tearDownClass()
+
+    @attr(type=['negative', 'gate'])
+    def test_create_with_enabled_False(self):
+        # Enabled should be a boolean, not a string like 'False'
+        interface = 'public'
+        url = data_utils.rand_name('url')
+        region = data_utils.rand_name('region')
+        self.assertRaises(exceptions.BadRequest, self.client.create_endpoint,
+                          self.service_id, interface, url, region=region,
+                          force_enabled='False')
+
+    @attr(type=['negative', 'gate'])
+    def test_create_with_enabled_True(self):
+        # Enabled should be a boolean, not a string like 'True'
+        interface = 'public'
+        url = data_utils.rand_name('url')
+        region = data_utils.rand_name('region')
+        self.assertRaises(exceptions.BadRequest, self.client.create_endpoint,
+                          self.service_id, interface, url, region=region,
+                          force_enabled='True')
+
+    def _assert_update_raises_bad_request(self, enabled):
+
+        # Create an endpoint
+        region1 = data_utils.rand_name('region')
+        url1 = data_utils.rand_name('url')
+        interface1 = 'public'
+        resp, endpoint_for_update = (
+            self.client.create_endpoint(self.service_id, interface1,
+                                        url1, region=region1, enabled=True))
+        self.addCleanup(self.client.delete_endpoint, endpoint_for_update['id'])
+
+        self.assertRaises(exceptions.BadRequest, self.client.update_endpoint,
+                          endpoint_for_update['id'], force_enabled=enabled)
+
+    @attr(type=['negative', 'gate'])
+    def test_update_with_enabled_False(self):
+        # Enabled should be a boolean, not a string like 'False'
+        self._assert_update_raises_bad_request('False')
+
+    @attr(type=['negative', 'gate'])
+    def test_update_with_enabled_True(self):
+        # Enabled should be a boolean, not a string like 'True'
+        self._assert_update_raises_bad_request('True')
+
+
+class EndpointsNegativeTestXML(EndpointsNegativeTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/object_storage/test_account_quotas.py b/tempest/api/object_storage/test_account_quotas.py
index b14adc0..a3098a5 100644
--- a/tempest/api/object_storage/test_account_quotas.py
+++ b/tempest/api/object_storage/test_account_quotas.py
@@ -68,7 +68,7 @@
         # Retrieve a ResellerAdmin auth data and use it to set a quota
         # on the client's account
         cls.reselleradmin_auth_data = \
-            cls.os_reselleradmin.get_auth_provider().auth_data
+            cls.os_reselleradmin.auth_provider.auth_data
 
     def setUp(self):
         super(AccountQuotasTest, self).setUp()
diff --git a/tempest/api/object_storage/test_account_quotas_negative.py b/tempest/api/object_storage/test_account_quotas_negative.py
index 402cd90..7648ea1 100644
--- a/tempest/api/object_storage/test_account_quotas_negative.py
+++ b/tempest/api/object_storage/test_account_quotas_negative.py
@@ -68,7 +68,7 @@
         # Retrieve a ResellerAdmin auth data and use it to set a quota
         # on the client's account
         cls.reselleradmin_auth_data = \
-            cls.os_reselleradmin.get_auth_provider().auth_data
+            cls.os_reselleradmin.auth_provider.auth_data
 
     def setUp(self):
         super(AccountQuotasNegativeTest, self).setUp()
diff --git a/tempest/api/object_storage/test_account_services_negative.py b/tempest/api/object_storage/test_account_services_negative.py
index ea93aa3..71eaab5 100644
--- a/tempest/api/object_storage/test_account_services_negative.py
+++ b/tempest/api/object_storage/test_account_services_negative.py
@@ -31,7 +31,7 @@
         test_os = clients.Manager(self.data.test_user,
                                   self.data.test_password,
                                   self.data.test_tenant)
-        test_auth_provider = test_os.get_auth_provider()
+        test_auth_provider = test_os.auth_provider
         # Get auth for the test user
         test_auth_provider.auth_data
 
diff --git a/tempest/api/object_storage/test_container_acl.py b/tempest/api/object_storage/test_container_acl.py
index 085ef51..c865ee1 100644
--- a/tempest/api/object_storage/test_container_acl.py
+++ b/tempest/api/object_storage/test_container_acl.py
@@ -27,7 +27,7 @@
         test_os = clients.Manager(cls.data.test_user,
                                   cls.data.test_password,
                                   cls.data.test_tenant)
-        cls.test_auth_data = test_os.get_auth_provider().auth_data
+        cls.test_auth_data = test_os.auth_provider.auth_data
 
     @classmethod
     def tearDownClass(cls):
diff --git a/tempest/api/object_storage/test_container_acl_negative.py b/tempest/api/object_storage/test_container_acl_negative.py
index a5a0950..547bf87 100644
--- a/tempest/api/object_storage/test_container_acl_negative.py
+++ b/tempest/api/object_storage/test_container_acl_negative.py
@@ -29,7 +29,7 @@
         test_os = clients.Manager(cls.data.test_user,
                                   cls.data.test_password,
                                   cls.data.test_tenant)
-        cls.test_auth_data = test_os.get_auth_provider().auth_data
+        cls.test_auth_data = test_os.auth_provider.auth_data
 
     @classmethod
     def tearDownClass(cls):
diff --git a/tempest/api/volume/test_volumes_actions.py b/tempest/api/volume/test_volumes_actions.py
index a22ad32..b9ea3c1 100644
--- a/tempest/api/volume/test_volumes_actions.py
+++ b/tempest/api/volume/test_volumes_actions.py
@@ -44,7 +44,7 @@
     def tearDownClass(cls):
         # Delete the test instance
         cls.servers_client.delete_server(cls.server['id'])
-        cls.client.wait_for_resource_deletion(cls.server['id'])
+        cls.servers_client.wait_for_server_termination(cls.server['id'])
 
         super(VolumesActionsTest, cls).tearDownClass()
 
diff --git a/tempest/exceptions/__init__.py b/tempest/exceptions/__init__.py
index 06dee71..485f532 100644
--- a/tempest/exceptions/__init__.py
+++ b/tempest/exceptions/__init__.py
@@ -20,6 +20,10 @@
     message = "Invalid Configuration"
 
 
+class InvalidCredentials(base.TempestException):
+    message = "Invalid Credentials"
+
+
 class InvalidHttpSuccessCode(base.RestClientException):
     message = "The success code is different than the expected one"
 
diff --git a/tempest/manager.py b/tempest/manager.py
index 708447e..63235db 100644
--- a/tempest/manager.py
+++ b/tempest/manager.py
@@ -75,13 +75,12 @@
             tenant_name=CONF.identity.tenant_name
         )
 
-    def get_auth_provider(self, credentials=None):
-        auth_params = dict(client_type=getattr(self, 'client_type', None),
-                           interface=getattr(self, 'interface', None))
+    def get_auth_provider(self, credentials):
+        if credentials is None:
+            raise exceptions.InvalidCredentials(
+                'Credentials must be specified')
         auth_provider_class = self.get_auth_provider_class(self.auth_version)
-        # If invalid / incomplete credentials are provided, use default ones
-        if credentials is None or \
-                not auth_provider_class.check_credentials(credentials):
-            credentials = self.credentials
-        auth_params['credentials'] = credentials
-        return auth_provider_class(**auth_params)
+        return auth_provider_class(
+            client_type=getattr(self, 'client_type', None),
+            interface=getattr(self, 'interface', None),
+            credentials=credentials)
diff --git a/tempest/services/identity/v3/json/endpoints_client.py b/tempest/services/identity/v3/json/endpoints_client.py
index c3c1e15..f7a894b 100644
--- a/tempest/services/identity/v3/json/endpoints_client.py
+++ b/tempest/services/identity/v3/json/endpoints_client.py
@@ -36,9 +36,17 @@
         return resp, body['endpoints']
 
     def create_endpoint(self, service_id, interface, url, **kwargs):
-        """Create endpoint."""
+        """Create endpoint.
+
+        Normally this function wouldn't allow setting values that are not
+        allowed for 'enabled'. Use `force_enabled` to set a non-boolean.
+
+        """
         region = kwargs.get('region', None)
-        enabled = kwargs.get('enabled', None)
+        if 'force_enabled' in kwargs:
+            enabled = kwargs.get('force_enabled', None)
+        else:
+            enabled = kwargs.get('enabled', None)
         post_body = {
             'service_id': service_id,
             'interface': interface,
@@ -52,8 +60,13 @@
         return resp, body['endpoint']
 
     def update_endpoint(self, endpoint_id, service_id=None, interface=None,
-                        url=None, region=None, enabled=None):
-        """Updates an endpoint with given parameters."""
+                        url=None, region=None, enabled=None, **kwargs):
+        """Updates an endpoint with given parameters.
+
+        Normally this function wouldn't allow setting values that are not
+        allowed for 'enabled'. Use `force_enabled` to set a non-boolean.
+
+        """
         post_body = {}
         if service_id is not None:
             post_body['service_id'] = service_id
@@ -63,7 +76,9 @@
             post_body['url'] = url
         if region is not None:
             post_body['region'] = region
-        if enabled is not None:
+        if 'force_enabled' in kwargs:
+            post_body['enabled'] = kwargs['force_enabled']
+        elif enabled is not None:
             post_body['enabled'] = enabled
         post_body = json.dumps({'endpoint': post_body})
         resp, body = self.patch('endpoints/%s' % endpoint_id, post_body)
diff --git a/tempest/services/identity/v3/xml/endpoints_client.py b/tempest/services/identity/v3/xml/endpoints_client.py
index cc9aa65..a1f9811 100644
--- a/tempest/services/identity/v3/xml/endpoints_client.py
+++ b/tempest/services/identity/v3/xml/endpoints_client.py
@@ -62,11 +62,19 @@
         return resp, body
 
     def create_endpoint(self, service_id, interface, url, **kwargs):
-        """Create endpoint."""
+        """Create endpoint.
+
+        Normally this function wouldn't allow setting values that are not
+        allowed for 'enabled'. Use `force_enabled` to set a non-boolean.
+
+        """
         region = kwargs.get('region', None)
-        enabled = kwargs.get('enabled', None)
-        if enabled is not None:
-            enabled = str(enabled).lower()
+        if 'force_enabled' in kwargs:
+            enabled = kwargs['force_enabled']
+        else:
+            enabled = kwargs.get('enabled', None)
+            if enabled is not None:
+                enabled = str(enabled).lower()
         create_endpoint = common.Element("endpoint",
                                          xmlns=XMLNS,
                                          service_id=service_id,
@@ -79,8 +87,13 @@
         return resp, body
 
     def update_endpoint(self, endpoint_id, service_id=None, interface=None,
-                        url=None, region=None, enabled=None):
-        """Updates an endpoint with given parameters."""
+                        url=None, region=None, enabled=None, **kwargs):
+        """Updates an endpoint with given parameters.
+
+        Normally this function wouldn't allow setting values that are not
+        allowed for 'enabled'. Use `force_enabled` to set a non-boolean.
+
+        """
         doc = common.Document()
         endpoint = common.Element("endpoint")
         doc.append(endpoint)
@@ -93,8 +106,12 @@
             endpoint.add_attr("url", url)
         if region:
             endpoint.add_attr("region", region)
-        if enabled is not None:
+
+        if 'force_enabled' in kwargs:
+            endpoint.add_attr("enabled", kwargs['force_enabled'])
+        elif enabled is not None:
             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/test.py b/tempest/test.py
index 6290761..75eb6be 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -220,13 +220,11 @@
 
 def validate_tearDownClass():
     if at_exit_set:
-        raise RuntimeError("tearDownClass does not call the super's "
-                           "tearDownClass in these classes: "
-                           + str(at_exit_set) + "\n"
-                           "If you see the exception, with another "
-                           "exception please do not report this one! "
-                           "If you are changing tempest code, make sure you "
-                           "are calling the super class's tearDownClass!")
+        LOG.error(
+            "tearDownClass does not call the super's "
+            "tearDownClass in these classes: \n"
+            + str(at_exit_set))
+
 
 atexit.register(validate_tearDownClass)