Merge "Clean network scenarios"
diff --git a/HACKING.rst b/HACKING.rst
index e7e7651..c0df0fb 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -108,16 +108,36 @@
 
 Negative Tests
 --------------
-When adding negative tests to tempest there are 2 requirements. First the tests
-must be marked with a negative attribute. For example::
+Newly added negative tests should use the negative test framework. First step
+is to create an interface description in a json file under `etc/schemas`.
+These descriptions consists of two important sections for the test
+(one of those is mandatory):
 
-  @attr(type=negative)
-  def test_resource_no_uuid(self):
-    ...
+ - A resource (part of the URL of the request): Resources needed for a test
+ must be created in `setUpClass` and registered with `set_resource` e.g.:
+ `cls.set_resource("server", server['id'])`
 
-The second requirement is that all negative tests must be added to a negative
-test file. If such a file doesn't exist for the particular resource being
-tested a new test file should be added.
+ - A json schema: defines properties for a request.
+
+After that a test class must be added to automatically generate test scenarios
+out of the given interface description:
+
+    class SampeTestNegativeTestJSON(<your base class>, test.NegativeAutoTest):
+        _interface = 'json'
+        _service = 'compute'
+        _schema_file = 'compute/servers/get_console_output.json'
+        scenarios = test.NegativeAutoTest.generate_scenario(_schema_file)
+
+Negative tests must be marked with a negative attribute::
+
+    @test.attr(type=['negative', 'gate'])
+    def test_get_console_output(self):
+        self.execute(self._schema_file)
+
+All negative tests should be added into a separate negative test file.
+If such a file doesn't exist for the particular resource being tested a new
+test file should be added. Old XML based negative tests can be kept but should
+be renamed to `_xml.py`.
 
 Test skips because of Known Bugs
 --------------------------------
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index a2d3877..0f18f5e 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -320,6 +320,10 @@
 # If false, skip disk config tests (boolean value)
 #disk_config=true
 
+# A list of enabled compute extensions with a special entry
+# all which indicates every extension is enabled (list value)
+#api_extensions=all
+
 # A list of enabled v3 extensions with a special entry all
 # which indicates every extension is enabled (list value)
 #api_v3_extensions=all
@@ -582,16 +586,8 @@
 # Options defined in tempest.config
 #
 
-# A list of enabled extensions with a special entry all which
-# indicates every extension is enabled (list value)
-#api_extensions=all
-
-# A list of enabled extensions with a special entry all which
-# indicates every extension is enabled (list value)
-#api_extensions=all
-
-# A list of enabled extensions with a special entry all which
-# indicates every extension is enabled (list value)
+# A list of enabled network extensions with a special entry
+# all which indicates every extension is enabled (list value)
 #api_extensions=all
 
 
@@ -877,6 +873,10 @@
 # Runs Cinder volumes backup test (boolean value)
 #backup=true
 
+# A list of enabled volume extensions with a special entry all
+# which indicates every extension is enabled (list value)
+#api_extensions=all
+
 # Is the v1 volume API enabled (boolean value)
 #api_v1=true
 
diff --git a/setup.cfg b/setup.cfg
index 79f538f..a701572 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -4,8 +4,8 @@
 summary = OpenStack Integration Testing
 description-file =
     README.rst
-author = OpenStack QA
-author-email = openstack-qa@lists.openstack.org
+author = OpenStack
+author-email = openstack-dev@lists.openstack.org
 home-page = http://www.openstack.org/
 classifier =
     Intended Audience :: Information Technology
diff --git a/tempest/api/compute/v3/admin/test_quotas.py b/tempest/api/compute/v3/admin/test_quotas.py
index 3ebbdeb..b388b70 100644
--- a/tempest/api/compute/v3/admin/test_quotas.py
+++ b/tempest/api/compute/v3/admin/test_quotas.py
@@ -16,7 +16,6 @@
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
 from tempest import config
-from tempest import exceptions
 from tempest import test
 
 CONF = config.CONF
@@ -54,6 +53,22 @@
                          sorted(quota_set.keys()))
         self.assertEqual(quota_set['id'], self.demo_tenant_id)
 
+    @test.attr(type='smoke')
+    def test_get_quota_set_detail(self):
+        # Admin can get the detail of resource quota set for a tenant
+        expected_quota_set = self.default_quota_set | set(['id'])
+        expected_detail = {'reserved', 'limit', 'in_use'}
+        resp, quota_set = self.adm_client.get_quota_set_detail(
+            self.demo_tenant_id)
+        self.assertEqual(200, resp.status)
+        self.assertEqual(sorted(expected_quota_set), sorted(quota_set.keys()))
+        self.assertEqual(quota_set['id'], self.demo_tenant_id)
+        for quota in quota_set:
+            if quota == 'id':
+                continue
+            self.assertEqual(sorted(expected_detail),
+                             sorted(quota_set[quota].keys()))
+
     @test.attr(type='gate')
     def test_update_all_quota_resources_for_tenant(self):
         # Admin can update all the resource quota limits for a tenant
@@ -95,56 +110,3 @@
         resp, quota_set = self.adm_client.get_quota_set(tenant_id)
         self.assertEqual(200, resp.status)
         self.assertEqual(quota_set['ram'], 5120)
-
-    # TODO(afazekas): Add dedicated tenant to the skiped quota tests
-    # it can be moved into the setUpClass as well
-    @test.attr(type='gate')
-    def test_create_server_when_cpu_quota_is_full(self):
-        # Disallow server creation when tenant's vcpu quota is full
-        resp, quota_set = self.adm_client.get_quota_set(self.demo_tenant_id)
-        default_vcpu_quota = quota_set['cores']
-        vcpu_quota = 0  # Set the quota to zero to conserve resources
-
-        resp, quota_set = self.adm_client.update_quota_set(self.demo_tenant_id,
-                                                           force=True,
-                                                           cores=vcpu_quota)
-
-        self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
-                        cores=default_vcpu_quota)
-        self.assertRaises(exceptions.OverLimit, self.create_test_server)
-
-    @test.attr(type='gate')
-    def test_create_server_when_memory_quota_is_full(self):
-        # Disallow server creation when tenant's memory quota is full
-        resp, quota_set = self.adm_client.get_quota_set(self.demo_tenant_id)
-        default_mem_quota = quota_set['ram']
-        mem_quota = 0  # Set the quota to zero to conserve resources
-
-        self.adm_client.update_quota_set(self.demo_tenant_id,
-                                         force=True,
-                                         ram=mem_quota)
-
-        self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
-                        ram=default_mem_quota)
-        self.assertRaises(exceptions.OverLimit, self.create_test_server)
-
-    @test.attr(type='gate')
-    def test_update_quota_normal_user(self):
-        self.assertRaises(exceptions.Unauthorized,
-                          self.client.update_quota_set,
-                          self.demo_tenant_id,
-                          ram=0)
-
-    @test.attr(type=['negative', 'gate'])
-    def test_create_server_when_instances_quota_is_full(self):
-        # Once instances quota limit is reached, disallow server creation
-        resp, quota_set = self.adm_client.get_quota_set(self.demo_tenant_id)
-        default_instances_quota = quota_set['instances']
-        instances_quota = 0  # Set quota to zero to disallow server creation
-
-        self.adm_client.update_quota_set(self.demo_tenant_id,
-                                         force=True,
-                                         instances=instances_quota)
-        self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
-                        instances=default_instances_quota)
-        self.assertRaises(exceptions.OverLimit, self.create_test_server)
diff --git a/tempest/api/compute/v3/admin/test_quotas_negative.py b/tempest/api/compute/v3/admin/test_quotas_negative.py
new file mode 100644
index 0000000..c9f14f8
--- /dev/null
+++ b/tempest/api/compute/v3/admin/test_quotas_negative.py
@@ -0,0 +1,88 @@
+# Copyright 2013 OpenStack Foundation
+# 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 import exceptions
+from tempest import test
+
+
+class QuotasAdminNegativeV3Test(base.BaseV3ComputeAdminTest):
+    _interface = 'json'
+    force_tenant_isolation = True
+
+    @classmethod
+    def setUpClass(cls):
+        super(QuotasAdminNegativeV3Test, cls).setUpClass()
+        cls.client = cls.quotas_client
+        cls.adm_client = cls.quotas_admin_client
+
+        # NOTE(afazekas): these test cases should always create and use a new
+        # tenant most of them should be skipped if we can't do that
+        cls.demo_tenant_id = cls.isolated_creds.get_primary_user().get(
+            'tenantId')
+
+    # TODO(afazekas): Add dedicated tenant to the skiped quota tests
+    # it can be moved into the setUpClass as well
+    @test.attr(type=['negative', 'gate'])
+    def test_create_server_when_cpu_quota_is_full(self):
+        # Disallow server creation when tenant's vcpu quota is full
+        resp, quota_set = self.adm_client.get_quota_set(self.demo_tenant_id)
+        default_vcpu_quota = quota_set['cores']
+        vcpu_quota = 0  # Set the quota to zero to conserve resources
+
+        resp, quota_set = self.adm_client.update_quota_set(self.demo_tenant_id,
+                                                           force=True,
+                                                           cores=vcpu_quota)
+
+        self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
+                        cores=default_vcpu_quota)
+        self.assertRaises(exceptions.OverLimit, self.create_test_server)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_server_when_memory_quota_is_full(self):
+        # Disallow server creation when tenant's memory quota is full
+        resp, quota_set = self.adm_client.get_quota_set(self.demo_tenant_id)
+        default_mem_quota = quota_set['ram']
+        mem_quota = 0  # Set the quota to zero to conserve resources
+
+        self.adm_client.update_quota_set(self.demo_tenant_id,
+                                         force=True,
+                                         ram=mem_quota)
+
+        self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
+                        ram=default_mem_quota)
+        self.assertRaises(exceptions.OverLimit, self.create_test_server)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_update_quota_normal_user(self):
+        self.assertRaises(exceptions.Unauthorized,
+                          self.client.update_quota_set,
+                          self.demo_tenant_id,
+                          ram=0)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_server_when_instances_quota_is_full(self):
+        # Once instances quota limit is reached, disallow server creation
+        resp, quota_set = self.adm_client.get_quota_set(self.demo_tenant_id)
+        default_instances_quota = quota_set['instances']
+        instances_quota = 0  # Set quota to zero to disallow server creation
+
+        self.adm_client.update_quota_set(self.demo_tenant_id,
+                                         force=True,
+                                         instances=instances_quota)
+        self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
+                        instances=default_instances_quota)
+        self.assertRaises(exceptions.OverLimit, self.create_test_server)
diff --git a/tempest/api/compute/v3/servers/test_instance_actions.py b/tempest/api/compute/v3/servers/test_instance_actions.py
index d536871..c4f6e14 100644
--- a/tempest/api/compute/v3/servers/test_instance_actions.py
+++ b/tempest/api/compute/v3/servers/test_instance_actions.py
@@ -14,8 +14,7 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest import exceptions
-from tempest.test import attr
+from tempest import test
 
 
 class InstanceActionsV3Test(base.BaseV3ComputeTest):
@@ -29,7 +28,7 @@
         cls.request_id = resp['x-compute-request-id']
         cls.server_id = server['id']
 
-    @attr(type='gate')
+    @test.attr(type='gate')
     def test_list_instance_actions(self):
         # List actions of the provided server
         resp, body = self.client.reboot(self.server_id, 'HARD')
@@ -41,7 +40,7 @@
         self.assertTrue(any([i for i in body if i['action'] == 'create']))
         self.assertTrue(any([i for i in body if i['action'] == 'reboot']))
 
-    @attr(type='gate')
+    @test.attr(type='gate')
     def test_get_instance_action(self):
         # Get the action details of the provided server
         resp, body = self.client.get_instance_action(self.server_id,
@@ -49,15 +48,3 @@
         self.assertEqual(200, resp.status)
         self.assertEqual(self.server_id, body['instance_uuid'])
         self.assertEqual('create', body['action'])
-
-    @attr(type=['negative', 'gate'])
-    def test_list_instance_actions_invalid_server(self):
-        # List actions of the invalid server id
-        self.assertRaises(exceptions.NotFound,
-                          self.client.list_instance_actions, 'server-999')
-
-    @attr(type=['negative', 'gate'])
-    def test_get_instance_action_invalid_request(self):
-        # Get the action details of the provided server with invalid request
-        self.assertRaises(exceptions.NotFound, self.client.get_instance_action,
-                          self.server_id, '999')
diff --git a/tempest/api/compute/v3/servers/test_instance_actions_negative.py b/tempest/api/compute/v3/servers/test_instance_actions_negative.py
new file mode 100644
index 0000000..bd741e0
--- /dev/null
+++ b/tempest/api/compute/v3/servers/test_instance_actions_negative.py
@@ -0,0 +1,44 @@
+# 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 InstanceActionsNegativeV3Test(base.BaseV3ComputeTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(InstanceActionsNegativeV3Test, cls).setUpClass()
+        cls.client = cls.servers_client
+        resp, server = cls.create_test_server(wait_until='ACTIVE')
+        cls.server_id = server['id']
+
+    @test.attr(type=['negative', 'gate'])
+    def test_list_instance_actions_invalid_server(self):
+        # List actions of the invalid server id
+        invalid_server_id = data_utils.rand_uuid()
+        self.assertRaises(exceptions.NotFound,
+                          self.client.list_instance_actions, invalid_server_id)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_get_instance_action_invalid_request(self):
+        # Get the action details of the provided server with invalid request
+        invalid_request_id = 'req-' + data_utils.rand_uuid()
+        self.assertRaises(exceptions.NotFound, self.client.get_instance_action,
+                          self.server_id, invalid_request_id)
diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py
index d08dc34..45c895b 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -130,7 +130,10 @@
                 objlist = container_client.list_all_container_objects(cont)
                 # delete every object in the container
                 for obj in objlist:
-                    object_client.delete_object(cont, obj['name'])
+                    try:
+                        object_client.delete_object(cont, obj['name'])
+                    except exceptions.NotFound:
+                        pass
                 container_client.delete_container(cont)
             except exceptions.NotFound:
                 pass
diff --git a/tempest/common/waiters.py b/tempest/common/waiters.py
index dbeba8f..8e6b9fb 100644
--- a/tempest/common/waiters.py
+++ b/tempest/common/waiters.py
@@ -42,7 +42,7 @@
     timeout = client.build_timeout + extra_timeout
     while True:
         # NOTE(afazekas): Now the BUILD status only reached
-        # between the UNKOWN->ACTIVE transition.
+        # between the UNKNOWN->ACTIVE transition.
         # TODO(afazekas): enumerate and validate the stable status set
         if status == 'BUILD' and server_status != 'UNKNOWN':
             return
diff --git a/tempest/config.py b/tempest/config.py
index c92a04d..4380608 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -15,6 +15,7 @@
 
 from __future__ import print_function
 
+import logging as std_logging
 import os
 
 from oslo.config import cfg
@@ -235,8 +236,8 @@
                 help="If false, skip disk config tests"),
     cfg.ListOpt('api_extensions',
                 default=['all'],
-                help='A list of enabled extensions with a special entry all '
-                     'which indicates every extension is enabled'),
+                help='A list of enabled compute extensions with a special '
+                     'entry all which indicates every extension is enabled'),
     cfg.ListOpt('api_v3_extensions',
                 default=['all'],
                 help='A list of enabled v3 extensions with a special entry all'
@@ -372,8 +373,8 @@
 NetworkFeaturesGroup = [
     cfg.ListOpt('api_extensions',
                 default=['all'],
-                help='A list of enabled extensions with a special entry all '
-                     'which indicates every extension is enabled'),
+                help='A list of enabled network extensions with a special '
+                     'entry all which indicates every extension is enabled'),
 ]
 
 volume_group = cfg.OptGroup(name='volume',
@@ -430,8 +431,8 @@
                 help='Runs Cinder volumes backup test'),
     cfg.ListOpt('api_extensions',
                 default=['all'],
-                help='A list of enabled extensions with a special entry all '
-                     'which indicates every extension is enabled'),
+                help='A list of enabled volume extensions with a special '
+                     'entry all which indicates every extension is enabled'),
     cfg.BoolOpt('api_v1',
                 default=True,
                 help="Is the v1 volume API enabled"),
@@ -876,6 +877,9 @@
             self.compute_admin.password = self.identity.admin_password
             self.compute_admin.tenant_name = self.identity.admin_tenant_name
 
+        if parse_conf:
+            cfg.CONF.log_opt_values(LOG, std_logging.DEBUG)
+
 
 class TempestConfigProxy(object):
     _config = None
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 6757da6..1763808 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -404,7 +404,7 @@
                                             properties={'disk_format':
                                                         'qcow2'})
         except IOError:
-            LOG.debug("A qcow2 image was not got. Try to get a uec image.")
+            LOG.debug("A qcow2 image was not found. Try to get a uec image.")
             kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
             ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
             properties = {
diff --git a/tempest/services/compute/v3/json/quotas_client.py b/tempest/services/compute/v3/json/quotas_client.py
index a01b9d2..aa8bfaf 100644
--- a/tempest/services/compute/v3/json/quotas_client.py
+++ b/tempest/services/compute/v3/json/quotas_client.py
@@ -35,6 +35,14 @@
         body = json.loads(body)
         return resp, body['quota_set']
 
+    def get_quota_set_detail(self, tenant_id):
+        """Get the quota set detail for a tenant."""
+
+        url = 'os-quota-sets/%s/detail' % str(tenant_id)
+        resp, body = self.get(url)
+        body = json.loads(body)
+        return resp, body['quota_set']
+
     def get_default_quota_set(self, tenant_id):
         """List the default quota set for a tenant."""
 
diff --git a/tempest/tests/fake_config.py b/tempest/tests/fake_config.py
index 42237ca..41b0558 100644
--- a/tempest/tests/fake_config.py
+++ b/tempest/tests/fake_config.py
@@ -21,6 +21,9 @@
 
     class fake_identity(object):
         disable_ssl_certificate_validation = True
+        catalog_type = 'identity'
+        uri = 'http://fake_uri.com/auth'
+        uri_v3 = 'http://fake_uri_v3.com/auth'
 
     class fake_default_feature_enabled(object):
         api_extensions = ['all']
diff --git a/tempest/tests/fake_http.py b/tempest/tests/fake_http.py
index ac5f765..a09d5ba 100644
--- a/tempest/tests/fake_http.py
+++ b/tempest/tests/fake_http.py
@@ -17,7 +17,7 @@
 
 class fake_httplib2(object):
 
-    def __init__(self, return_type=None):
+    def __init__(self, return_type=None, *args, **kwargs):
         self.return_type = return_type
 
     def request(self, uri, method="GET", body=None, headers=None,
diff --git a/tempest/tests/fake_identity.py b/tempest/tests/fake_identity.py
new file mode 100644
index 0000000..ea2bd44
--- /dev/null
+++ b/tempest/tests/fake_identity.py
@@ -0,0 +1,156 @@
+# Copyright 2014 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 httplib2
+import json
+
+
+TOKEN = "fake_token"
+ALT_TOKEN = "alt_fake_token"
+
+# Fake Identity v2 constants
+COMPUTE_ENDPOINTS_V2 = {
+    "endpoints": [
+        {
+            "adminURL": "http://fake_url/api/admin",
+            "region": "NoMatchRegion",
+            "internalURL": "http://fake_url/api/internal",
+            "publicURL": "http://fake_url/api/public"
+        },
+        {
+            "adminURL": "http://fake_url/api/admin",
+            "region": "FakeRegion",
+            "internalURL": "http://fake_url/api/internal",
+            "publicURL": "http://fake_url/api/public"
+        },
+    ],
+    "type": "compute",
+    "name": "nova"
+}
+
+CATALOG_V2 = [COMPUTE_ENDPOINTS_V2, ]
+
+ALT_IDENTITY_V2_RESPONSE = {
+    "access": {
+        "token": {
+            "expires": "2020-01-01T00:00:10Z",
+            "id": ALT_TOKEN,
+            "tenant": {
+                "id": "fake_tenant_id"
+            },
+        },
+        "user": {
+            "id": "fake_user_id",
+        },
+        "serviceCatalog": CATALOG_V2,
+    },
+}
+
+IDENTITY_V2_RESPONSE = {
+    "access": {
+        "token": {
+            "expires": "2020-01-01T00:00:10Z",
+            "id": TOKEN,
+            "tenant": {
+                "id": "fake_tenant_id"
+            },
+        },
+        "user": {
+            "id": "fake_user_id",
+        },
+        "serviceCatalog": CATALOG_V2,
+    },
+}
+
+# Fake Identity V3 constants
+COMPUTE_ENDPOINTS_V3 = {
+    "endpoints": [
+        {
+            "id": "fake_service",
+            "interface": "public",
+            "region": "NoMatchRegion",
+            "url": "http://fake_url/v3"
+        },
+        {
+            "id": "another_fake_service",
+            "interface": "public",
+            "region": "FakeRegion",
+            "url": "http://fake_url/v3"
+        }
+    ],
+    "type": "compute",
+    "id": "fake_compute_endpoint"
+}
+
+CATALOG_V3 = [COMPUTE_ENDPOINTS_V3, ]
+
+IDENTITY_V3_RESPONSE = {
+    "token": {
+        "methods": [
+            "token",
+            "password"
+        ],
+        "expires_at": "2020-01-01T00:00:10.000123Z",
+        "project": {
+            "domain": {
+                "id": "fake_id",
+                "name": "fake"
+            },
+            "id": "project_id",
+            "name": "project_name"
+        },
+        "user": {
+            "domain": {
+                "id": "domain_id",
+                "name": "domain_name"
+            },
+            "id": "fake_user_id",
+            "name": "username"
+        },
+        "issued_at": "2013-05-29T16:55:21.468960Z",
+        "catalog": CATALOG_V3
+    }
+}
+
+ALT_IDENTITY_V3 = IDENTITY_V3_RESPONSE
+
+
+def _fake_v3_response(self, uri, method="GET", body=None, headers=None,
+                      redirections=5, connection_type=None):
+    fake_headers = {
+        "status": "201",
+        "x-subject-token": TOKEN
+    }
+    return (httplib2.Response(fake_headers),
+            json.dumps(IDENTITY_V3_RESPONSE))
+
+
+def _fake_v2_response(self, uri, method="GET", body=None, headers=None,
+                      redirections=5, connection_type=None):
+    return (httplib2.Response({"status": "200"}),
+            json.dumps(IDENTITY_V2_RESPONSE))
+
+
+def _fake_auth_failure_response():
+    # the response body isn't really used in this case, but lets send it anyway
+    # to have a safe check in some future change on the rest client.
+    body = {
+        "unauthorized": {
+            "message": "Unauthorized",
+            "code": "401"
+        }
+    }
+    return httplib2.Response({"status": "401"}), json.dumps(body)
diff --git a/tempest/tests/files/setup.cfg b/tempest/tests/files/setup.cfg
index 8639baa..f6f9f73 100644
--- a/tempest/tests/files/setup.cfg
+++ b/tempest/tests/files/setup.cfg
@@ -2,8 +2,8 @@
 name = tempest_unit_tests
 version = 1
 summary = Fake Project for testing wrapper scripts
-author = OpenStack QA
-author-email = openstack-qa@lists.openstack.org
+author = OpenStack
+author-email = openstack-dev@lists.openstack.org
 home-page = http://www.openstack.org/
 classifier =
     Intended Audience :: Information Technology
diff --git a/tempest/tests/test_auth.py b/tempest/tests/test_auth.py
new file mode 100644
index 0000000..5346052
--- /dev/null
+++ b/tempest/tests/test_auth.py
@@ -0,0 +1,210 @@
+# Copyright 2014 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 copy
+
+from tempest import auth
+from tempest.common import http
+from tempest import config
+from tempest import exceptions
+from tempest.openstack.common.fixture import mockpatch
+from tempest.tests import base
+from tempest.tests import fake_config
+from tempest.tests import fake_http
+from tempest.tests import fake_identity
+
+
+class BaseAuthTestsSetUp(base.TestCase):
+    _auth_provider_class = None
+    credentials = {
+        'username': 'fake_user',
+        'password': 'fake_pwd',
+        'tenant_name': 'fake_tenant'
+    }
+
+    def _auth(self, credentials, **params):
+        """
+        returns auth method according to keystone
+        """
+        return self._auth_provider_class(credentials, **params)
+
+    def setUp(self):
+        super(BaseAuthTestsSetUp, self).setUp()
+        self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakeConfig)
+        self.fake_http = fake_http.fake_httplib2(return_type=200)
+        self.stubs.Set(http.ClosingHttp, 'request', self.fake_http.request)
+        self.auth_provider = self._auth(self.credentials)
+
+
+class TestBaseAuthProvider(BaseAuthTestsSetUp):
+    """
+    This tests auth.AuthProvider class which is base for the other so we
+    obviously don't test not implemented method or the ones which strongly
+    depends on them.
+    """
+    _auth_provider_class = auth.AuthProvider
+
+    def test_check_credentials_is_dict(self):
+        self.assertTrue(self.auth_provider.check_credentials({}))
+
+    def test_check_credentials_bad_type(self):
+        self.assertFalse(self.auth_provider.check_credentials([]))
+
+    def test_instantiate_with_bad_credentials_type(self):
+        """
+        Assure that credentials with bad type fail with TypeError
+        """
+        self.assertRaises(TypeError, self._auth, [])
+
+    def test_auth_data_property(self):
+        self.assertRaises(NotImplementedError, getattr, self.auth_provider,
+                          'auth_data')
+
+    def test_auth_data_property_when_cache_exists(self):
+        self.auth_provider.cache = 'foo'
+        self.useFixture(mockpatch.PatchObject(self.auth_provider,
+                                              'is_expired',
+                                              return_value=False))
+        self.assertEqual('foo', getattr(self.auth_provider, 'auth_data'))
+
+    def test_delete_auth_data_property_through_deleter(self):
+        self.auth_provider.cache = 'foo'
+        del self.auth_provider.auth_data
+        self.assertIsNone(self.auth_provider.cache)
+
+    def test_delete_auth_data_property_through_clear_auth(self):
+        self.auth_provider.cache = 'foo'
+        self.auth_provider.clear_auth()
+        self.assertIsNone(self.auth_provider.cache)
+
+    def test_set_and_reset_alt_auth_data(self):
+        self.auth_provider.set_alt_auth_data('foo', 'bar')
+        self.assertEqual(self.auth_provider.alt_part, 'foo')
+        self.assertEqual(self.auth_provider.alt_auth_data, 'bar')
+
+        self.auth_provider.reset_alt_auth_data()
+        self.assertIsNone(self.auth_provider.alt_part)
+        self.assertIsNone(self.auth_provider.alt_auth_data)
+
+
+class TestKeystoneV2AuthProvider(BaseAuthTestsSetUp):
+    _auth_provider_class = auth.KeystoneV2AuthProvider
+
+    def setUp(self):
+        super(TestKeystoneV2AuthProvider, self).setUp()
+        self.stubs.Set(http.ClosingHttp, 'request',
+                       fake_identity._fake_v2_response)
+        self.target_url = 'test_api'
+
+    def _get_fake_alt_identity(self):
+        return fake_identity.ALT_IDENTITY_V2_RESPONSE['access']
+
+    def _get_result_url_from_fake_identity(self):
+        return fake_identity.COMPUTE_ENDPOINTS_V2['endpoints'][1]['publicURL']
+
+    def _get_token_from_fake_identity(self):
+        return fake_identity.TOKEN
+
+    def _test_request_helper(self):
+        filters = {
+            'service': 'compute',
+            'endpoint_type': 'publicURL',
+            'region': 'fakeRegion'
+        }
+
+        url, headers, body = self.auth_provider.auth_request('GET',
+                                                             self.target_url,
+                                                             filters=filters)
+
+        result_url = self._get_result_url_from_fake_identity()
+        self.assertEqual(url, result_url + '/' + self.target_url)
+        self.assertEqual(self._get_token_from_fake_identity(),
+                         headers['X-Auth-Token'])
+        self.assertEqual(body, None)
+
+    def test_request(self):
+        self._test_request_helper()
+
+    def test_request_with_alt_auth(self):
+        self.auth_provider.set_alt_auth_data(
+            'body',
+            (fake_identity.ALT_TOKEN, self._get_fake_alt_identity()))
+        self._test_request_helper()
+        # Assert alt auth data is clear after it
+        self.assertIsNone(self.auth_provider.alt_part)
+        self.assertIsNone(self.auth_provider.alt_auth_data)
+
+    def test_request_with_bad_service(self):
+        filters = {
+            'service': 'BAD_SERVICE',
+            'endpoint_type': 'publicURL',
+            'region': 'fakeRegion'
+        }
+        self.assertRaises(exceptions.EndpointNotFound,
+                          self.auth_provider.auth_request, 'GET',
+                          'http://fakeurl.com/fake_api', filters=filters)
+
+    def test_request_without_service(self):
+        filters = {
+            'service': None,
+            'endpoint_type': 'publicURL',
+            'region': 'fakeRegion'
+        }
+        self.assertRaises(exceptions.EndpointNotFound,
+                          self.auth_provider.auth_request, 'GET',
+                          'http://fakeurl.com/fake_api', filters=filters)
+
+    def test_check_credentials_missing_attribute(self):
+        for attr in ['username', 'password']:
+            cred = copy.copy(self.credentials)
+            del cred[attr]
+            self.assertFalse(self.auth_provider.check_credentials(cred))
+
+    def test_check_credentials_not_scoped_missing_tenant_name(self):
+        cred = copy.copy(self.credentials)
+        del cred['tenant_name']
+        self.assertTrue(self.auth_provider.check_credentials(cred,
+                                                             scoped=False))
+
+    def test_check_credentials_missing_tenant_name(self):
+        cred = copy.copy(self.credentials)
+        del cred['tenant_name']
+        self.assertFalse(self.auth_provider.check_credentials(cred))
+
+
+class TestKeystoneV3AuthProvider(TestKeystoneV2AuthProvider):
+    _auth_provider_class = auth.KeystoneV3AuthProvider
+    credentials = {
+        'username': 'fake_user',
+        'password': 'fake_pwd',
+        'tenant_name': 'fake_tenant',
+        'domain_name': 'fake_domain_name',
+    }
+
+    def setUp(self):
+        super(TestKeystoneV3AuthProvider, self).setUp()
+        self.stubs.Set(http.ClosingHttp, 'request',
+                       fake_identity._fake_v3_response)
+
+    def _get_fake_alt_identity(self):
+        return fake_identity.ALT_IDENTITY_V3['token']
+
+    def _get_result_url_from_fake_identity(self):
+        return fake_identity.COMPUTE_ENDPOINTS_V3['endpoints'][1]['url']
+
+    def test_check_credentials_missing_tenant_name(self):
+        cred = copy.copy(self.credentials)
+        del cred['domain_name']
+        self.assertFalse(self.auth_provider.check_credentials(cred))