Merge "Apply other "get" rule of GET to image v2 client"
diff --git a/etc/javelin-resources.yaml.sample b/etc/javelin-resources.yaml.sample
new file mode 100644
index 0000000..fb270a4
--- /dev/null
+++ b/etc/javelin-resources.yaml.sample
@@ -0,0 +1,65 @@
+tenants:
+  - javelin
+  - discuss
+
+users:
+  - name: javelin
+    pass: gungnir
+    tenant: javelin
+  - name: javelin2
+    pass: gungnir2
+    tenant: discuss
+
+secgroups:
+  - name: secgroup1
+    owner: javelin
+    description: SecurityGroup1
+    rules:
+      - 'icmp -1 -1 0.0.0.0/0'
+      - 'tcp 22 22 0.0.0.0/0'
+  - name: secgroup2
+    owner: javelin2
+    description: SecurityGroup2
+    rules:
+      - 'tcp 80 80 0.0.0.0/0'
+
+images:
+  - name: cirros1
+    owner: javelin
+    imgdir: images
+    file: cirros.img
+    container_format: bare
+    disk_format: qcow2
+  - name: cirros2
+    owner: javelin2
+    imgdir: files/images/cirros-0.3.2-x86_64-uec
+    file: cirros-0.3.2-x86_64-blank.img
+    container_format: ami
+    disk_format: ami
+    aki: cirros-0.3.2-x86_64-vmlinuz
+    ari: cirros-0.3.2-x86_64-initrd
+
+networks:
+  - name: network1
+    owner: javelin
+  - name: network2
+    owner: javelin2
+
+subnets:
+  - name: net1-subnet1
+    range: 10.1.0.0/24
+    network: network1
+    owner: javelin
+  - name: net2-subnet2
+    range: 192.168.1.0/24
+    network: network2
+    owner: javelin2
+
+objects:
+  - container: container1
+    name: object1
+    owner: javelin
+    file: /etc/hosts
+    swift_role: Member
+
+telemetry: true
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index 7fe8858..cb0031d 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,17 +4,17 @@
 pbr>=0.11,<2.0
 anyjson>=0.3.3
 httplib2>=0.7.5
-jsonschema>=2.0.0,<3.0.0
+jsonschema>=2.0.0,<3.0.0,!=2.5.0
 testtools>=0.9.36,!=1.2.0
 boto>=2.32.1
 paramiko>=1.13.0
 netaddr>=0.7.12
 testrepository>=0.0.18
 pyOpenSSL>=0.11
-oslo.concurrency>=1.8.0         # Apache-2.0
+oslo.concurrency>=2.0.0         # Apache-2.0
 oslo.config>=1.11.0  # Apache-2.0
 oslo.i18n>=1.5.0  # Apache-2.0
-oslo.log>=1.0.0  # Apache-2.0
+oslo.log>=1.2.0  # Apache-2.0
 oslo.serialization>=1.4.0               # Apache-2.0
 oslo.utils>=1.4.0                       # Apache-2.0
 six>=1.9.0
diff --git a/tempest/api/identity/v2/test_api_discovery.py b/tempest/api/identity/v2/test_api_discovery.py
new file mode 100644
index 0000000..8132ee1
--- /dev/null
+++ b/tempest/api/identity/v2/test_api_discovery.py
@@ -0,0 +1,57 @@
+# Copyright 2015 OpenStack Foundation.
+# Copyright 2015, Red Hat, Inc.
+#
+#    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 import test
+
+
+class TestApiDiscovery(base.BaseIdentityV2Test):
+    """Tests for API discovery features."""
+
+    @test.attr(type='smoke')
+    @test.idempotent_id('ea889a68-a15f-4166-bfb1-c12456eae853')
+    def test_api_version_resources(self):
+        descr = self.non_admin_client.get_api_description()
+        expected_resources = ('id', 'links', 'media-types', 'status',
+                              'updated')
+
+        keys = descr.keys()
+        for res in expected_resources:
+            self.assertIn(res, keys)
+
+    @test.attr(type='smoke')
+    @test.idempotent_id('007a0be0-78fe-4fdb-bbee-e9216cc17bb2')
+    def test_api_media_types(self):
+        descr = self.non_admin_client.get_api_description()
+        # Get MIME type bases and descriptions
+        media_types = [(media_type['base'], media_type['type']) for
+                       media_type in descr['media-types']]
+        # These are supported for API version 2
+        supported_types = [('application/json',
+                            'application/vnd.openstack.identity-v2.0+json')]
+
+        # Check if supported types exist in response body
+        for s_type in supported_types:
+            self.assertIn(s_type, media_types)
+
+    @test.attr(type='smoke')
+    @test.idempotent_id('77fd6be0-8801-48e6-b9bf-38cdd2f253ec')
+    def test_api_version_statuses(self):
+        descr = self.non_admin_client.get_api_description()
+        status = descr['status'].lower()
+        supported_statuses = ['current', 'stable', 'experimental',
+                              'supported', 'deprecated']
+
+        self.assertIn(status, supported_statuses)
diff --git a/tempest/api/identity/v3/test_api_discovery.py b/tempest/api/identity/v3/test_api_discovery.py
new file mode 100644
index 0000000..2ec8ad8
--- /dev/null
+++ b/tempest/api/identity/v3/test_api_discovery.py
@@ -0,0 +1,57 @@
+# Copyright 2015 OpenStack Foundation.
+# Copyright 2015, Red Hat, Inc.
+#
+#    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 import test
+
+
+class TestApiDiscovery(base.BaseIdentityV3Test):
+    """Tests for API discovery features."""
+
+    @test.attr(type='smoke')
+    @test.idempotent_id('b9232f5e-d9e5-4d97-b96c-28d3db4de1bd')
+    def test_api_version_resources(self):
+        descr = self.non_admin_client.get_api_description()
+        expected_resources = ('id', 'links', 'media-types', 'status',
+                              'updated')
+
+        keys = descr.keys()
+        for res in expected_resources:
+            self.assertIn(res, keys)
+
+    @test.attr(type='smoke')
+    @test.idempotent_id('657c1970-4722-4189-8831-7325f3bc4265')
+    def test_api_media_types(self):
+        descr = self.non_admin_client.get_api_description()
+        # Get MIME type bases and descriptions
+        media_types = [(media_type['base'], media_type['type']) for
+                       media_type in descr['media-types']]
+        # These are supported for API version 2
+        supported_types = [('application/json',
+                            'application/vnd.openstack.identity-v3+json')]
+
+        # Check if supported types exist in response body
+        for s_type in supported_types:
+            self.assertIn(s_type, media_types)
+
+    @test.attr(type='smoke')
+    @test.idempotent_id('8879a470-abfb-47bb-bb8d-5a7fd279ad1e')
+    def test_api_version_statuses(self):
+        descr = self.non_admin_client.get_api_description()
+        status = descr['status'].lower()
+        supported_statuses = ['current', 'stable', 'experimental',
+                              'supported', 'deprecated']
+
+        self.assertIn(status, supported_statuses)
diff --git a/tempest/api/network/admin/test_l3_agent_scheduler.py b/tempest/api/network/admin/test_l3_agent_scheduler.py
index 160cc06..2ff8897 100644
--- a/tempest/api/network/admin/test_l3_agent_scheduler.py
+++ b/tempest/api/network/admin/test_l3_agent_scheduler.py
@@ -72,15 +72,22 @@
         # query and setup steps are only required if the extension is available
         # and only if the router's default type is distributed.
         if test.is_extension_enabled('dvr', 'network'):
-            is_dvr_router = cls.admin_client.show_router(
+            cls.is_dvr_router = cls.admin_client.show_router(
                 cls.router['id'])['router'].get('distributed', False)
-            if is_dvr_router:
+            if cls.is_dvr_router:
                 cls.network = cls.create_network()
-                cls.create_subnet(cls.network)
+                cls.subnet = cls.create_subnet(cls.network)
                 cls.port = cls.create_port(cls.network)
                 cls.client.add_router_interface_with_port_id(
                     cls.router['id'], cls.port['id'])
 
+    @classmethod
+    def resource_cleanup(cls):
+        if cls.is_dvr_router:
+            cls.client.remove_router_interface_with_port_id(
+                cls.router['id'], cls.port['id'])
+        super(L3AgentSchedulerTestJSON, cls).resource_cleanup()
+
     @test.idempotent_id('b7ce6e89-e837-4ded-9b78-9ed3c9c6a45a')
     def test_list_routers_on_l3_agent(self):
         self.admin_client.list_routers_on_l3_agent(self.agent['id'])
diff --git a/tempest/api/network/test_extensions.py b/tempest/api/network/test_extensions.py
index e9f1bf4..be7174b 100644
--- a/tempest/api/network/test_extensions.py
+++ b/tempest/api/network/test_extensions.py
@@ -57,7 +57,6 @@
             self.assertIn('updated', ext_details.keys())
             self.assertIn('name', ext_details.keys())
             self.assertIn('description', ext_details.keys())
-            self.assertIn('namespace', ext_details.keys())
             self.assertIn('links', ext_details.keys())
             self.assertIn('alias', ext_details.keys())
             self.assertEqual(ext_details['name'], ext_name)
diff --git a/tempest/services/identity/v2/json/identity_client.py b/tempest/services/identity/v2/json/identity_client.py
index 039f9bb..c5f7338 100644
--- a/tempest/services/identity/v2/json/identity_client.py
+++ b/tempest/services/identity/v2/json/identity_client.py
@@ -18,6 +18,13 @@
 
 class IdentityClientJSON(service_client.ServiceClient):
 
+    def get_api_description(self):
+        """Retrieves info about the v2.0 Identity API"""
+        url = ''
+        resp, body = self.get(url)
+        self.expected_success([200, 203], resp.status)
+        return service_client.ResponseBody(resp, self._parse_resp(body))
+
     def has_admin_extensions(self):
         """
         Returns True if the KSADM Admin Extensions are supported
diff --git a/tempest/services/identity/v3/json/identity_client.py b/tempest/services/identity/v3/json/identity_client.py
index f3d02a8..30fb3e1 100644
--- a/tempest/services/identity/v3/json/identity_client.py
+++ b/tempest/services/identity/v3/json/identity_client.py
@@ -23,6 +23,13 @@
 class IdentityV3ClientJSON(service_client.ServiceClient):
     api_version = "v3"
 
+    def get_api_description(self):
+        """Retrieves info about the v3 Identity API"""
+        url = ''
+        resp, body = self.get(url)
+        self.expected_success(200, resp.status)
+        return service_client.ResponseBody(resp, self._parse_resp(body))
+
     def create_user(self, user_name, password=None, project_id=None,
                     email=None, domain_id='default', **kwargs):
         """Creates a user."""
diff --git a/test-requirements.txt b/test-requirements.txt
index 32f33bc..7169610 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -10,4 +10,4 @@
 mock>=1.0
 coverage>=3.6
 oslotest>=1.5.1  # Apache-2.0
-stevedore>=1.3.0  # Apache-2.0
+stevedore>=1.5.0  # Apache-2.0