Merge "Fix the way to get tempest.conf in README.rst"
diff --git a/requirements.txt b/requirements.txt
index 415eaa5..f00de0d 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -15,7 +15,7 @@
 oslo.concurrency>=2.3.0 # Apache-2.0
 oslo.config>=1.11.0 # Apache-2.0
 oslo.i18n>=1.5.0 # Apache-2.0
-oslo.log>=1.6.0 # Apache-2.0
+oslo.log>=1.8.0 # Apache-2.0
 oslo.serialization>=1.4.0 # Apache-2.0
 oslo.utils>=1.9.0 # Apache-2.0
 six>=1.9.0
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index a75cb3e..6160844 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -305,12 +305,20 @@
             params = {'ip': ip}
         else:
             params = {'ip6': ip}
+        # capture all servers in case something goes wrong
+        all_servers = self.client.list_servers(detail=True)
         body = self.client.list_servers(**params)
         servers = body['servers']
 
-        self.assertIn(self.s1_name, map(lambda x: x['name'], servers))
-        self.assertIn(self.s2_name, map(lambda x: x['name'], servers))
-        self.assertIn(self.s3_name, map(lambda x: x['name'], servers))
+        self.assertIn(self.s1_name, map(lambda x: x['name'], servers),
+                      "%s not found in %s, all servers %s" %
+                      (self.s1_name, servers, all_servers))
+        self.assertIn(self.s2_name, map(lambda x: x['name'], servers),
+                      "%s not found in %s, all servers %s" %
+                      (self.s2_name, servers, all_servers))
+        self.assertIn(self.s3_name, map(lambda x: x['name'], servers),
+                      "%s not found in %s, all servers %s" %
+                      (self.s3_name, servers, all_servers))
 
     @test.idempotent_id('67aec2d0-35fe-4503-9f92-f13272b867ed')
     def test_list_servers_detailed_limit_results(self):
diff --git a/tempest/api/identity/admin/v2/test_endpoints.py b/tempest/api/identity/admin/v2/test_endpoints.py
new file mode 100644
index 0000000..3af2e90
--- /dev/null
+++ b/tempest/api/identity/admin/v2/test_endpoints.py
@@ -0,0 +1,90 @@
+# Copyright 2013 OpenStack Foundation
+# 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 test
+
+
+class EndPointsTestJSON(base.BaseIdentityV2AdminTest):
+
+    @classmethod
+    def resource_setup(cls):
+        super(EndPointsTestJSON, cls).resource_setup()
+        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')
+        cls.service_data =\
+            cls.client.create_service(s_name, s_type,
+                                      description=s_description)
+        cls.service_id = cls.service_data['id']
+        cls.service_ids.append(cls.service_id)
+        # Create endpoints so as to use for LIST and GET test cases
+        cls.setup_endpoints = list()
+        for i in range(2):
+            region = data_utils.rand_name('region')
+            url = data_utils.rand_url()
+            endpoint = cls.client.create_endpoint(cls.service_id,
+                                                  region,
+                                                  publicurl=url,
+                                                  adminurl=url,
+                                                  internalurl=url)
+            # list_endpoints() will return 'enabled' field
+            endpoint['enabled'] = True
+            cls.setup_endpoints.append(endpoint)
+
+    @classmethod
+    def resource_cleanup(cls):
+        for e in cls.setup_endpoints:
+            cls.client.delete_endpoint(e['id'])
+        for s in cls.service_ids:
+            cls.client.delete_service(s)
+        super(EndPointsTestJSON, cls).resource_cleanup()
+
+    @test.idempotent_id('11f590eb-59d8-4067-8b2b-980c7f387f51')
+    def test_list_endpoints(self):
+        # Get a list of endpoints
+        fetched_endpoints = self.client.list_endpoints()
+        # Asserting LIST endpoints
+        missing_endpoints =\
+            [e for e in self.setup_endpoints if e not in fetched_endpoints]
+        self.assertEqual(0, len(missing_endpoints),
+                         "Failed to find endpoint %s in fetched list" %
+                         ', '.join(str(e) for e in missing_endpoints))
+
+    @test.idempotent_id('9974530a-aa28-4362-8403-f06db02b26c1')
+    def test_create_list_delete_endpoint(self):
+        region = data_utils.rand_name('region')
+        url = data_utils.rand_url()
+        endpoint = self.client.create_endpoint(self.service_id,
+                                               region,
+                                               publicurl=url,
+                                               adminurl=url,
+                                               internalurl=url)
+        # Asserting Create Endpoint response body
+        self.assertIn('id', endpoint)
+        self.assertEqual(region, endpoint['region'])
+        self.assertEqual(url, endpoint['publicurl'])
+        # Checking if created endpoint is present in the list of endpoints
+        fetched_endpoints = self.client.list_endpoints()
+        fetched_endpoints_id = [e['id'] for e in fetched_endpoints]
+        self.assertIn(endpoint['id'], fetched_endpoints_id)
+        # Deleting the endpoint created in this method
+        self.client.delete_endpoint(endpoint['id'])
+        # Checking whether endpoint is deleted successfully
+        fetched_endpoints = self.client.list_endpoints()
+        fetched_endpoints_id = [e['id'] for e in fetched_endpoints]
+        self.assertNotIn(endpoint['id'], fetched_endpoints_id)
diff --git a/tempest/clients.py b/tempest/clients.py
index e32d401..b3fb8a8 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -344,15 +344,25 @@
     def _set_identity_clients(self):
         params = {
             'service': CONF.identity.catalog_type,
-            'region': CONF.identity.region,
-            'endpoint_type': 'adminURL'
+            'region': CONF.identity.region
         }
         params.update(self.default_params_with_timeout_values)
-
+        params_v2_admin = params.copy()
+        params_v2_admin['endpoint_type'] = CONF.identity.v2_admin_endpoint_type
+        # Client uses admin endpoint type of Keystone API v2
         self.identity_client = IdentityClient(self.auth_provider,
-                                              **params)
+                                              **params_v2_admin)
+        params_v2_public = params.copy()
+        params_v2_public['endpoint_type'] = (
+            CONF.identity.v2_public_endpoint_type)
+        # Client uses public endpoint type of Keystone API v2
+        self.identity_public_client = IdentityClient(self.auth_provider,
+                                                     **params_v2_public)
+        params_v3 = params.copy()
+        params_v3['endpoint_type'] = CONF.identity.v3_endpoint_type
+        # Client uses the endpoint type of Keystone API v3
         self.identity_v3_client = IdentityV3Client(self.auth_provider,
-                                                   **params)
+                                                   **params_v3)
         self.endpoints_client = EndPointClient(self.auth_provider,
                                                **params)
         self.service_client = ServiceClient(self.auth_provider, **params)
diff --git a/tempest/common/validation_resources.py b/tempest/common/validation_resources.py
index 402638d..14730cf 100644
--- a/tempest/common/validation_resources.py
+++ b/tempest/common/validation_resources.py
@@ -23,17 +23,17 @@
 
 
 def create_ssh_security_group(os, add_rule=False):
-    security_group_client = os.security_groups_client
+    security_groups_client = os.security_groups_client
+    security_group_rules_client = os.security_group_rules_client
     sg_name = data_utils.rand_name('securitygroup-')
     sg_description = data_utils.rand_name('description-')
-    security_group = \
-        security_group_client.create_security_group(name=sg_name,
-                                                    description=sg_description)
+    security_group = security_groups_client.create_security_group(
+        name=sg_name, description=sg_description)
     if add_rule:
-        security_group_client.create_security_group_rule(
+        security_group_rules_client.create_security_group_rule(
             parent_group_id=security_group['id'], ip_protocol='tcp',
             from_port=22, to_port=22)
-        security_group_client.create_security_group_rule(
+        security_group_rules_client.create_security_group_rule(
             parent_group_id=security_group['id'], ip_protocol='icmp',
             from_port=-1, to_port=-1)
     LOG.debug("SSH Validation resource security group with tcp and icmp "
diff --git a/tempest/config.py b/tempest/config.py
index 48417c3..0262d1b 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -112,11 +112,30 @@
                     "services' region name unless they are set explicitly. "
                     "If no such region is found in the service catalog, the "
                     "first found one is used."),
-    cfg.StrOpt('endpoint_type',
+    cfg.StrOpt('v2_admin_endpoint_type',
+               default='adminURL',
+               choices=['public', 'admin', 'internal',
+                        'publicURL', 'adminURL', 'internalURL'],
+               help="The admin endpoint type to use for OpenStack Identity "
+                    "(Keystone) API v2",
+               deprecated_opts=[cfg.DeprecatedOpt('endpoint_type',
+                                                  group='identity')]),
+    cfg.StrOpt('v2_public_endpoint_type',
                default='publicURL',
                choices=['public', 'admin', 'internal',
                         'publicURL', 'adminURL', 'internalURL'],
-               help="The endpoint type to use for the identity service."),
+               help="The public endpoint type to use for OpenStack Identity "
+                    "(Keystone) API v2",
+               deprecated_opts=[cfg.DeprecatedOpt('endpoint_type',
+                                                  group='identity')]),
+    cfg.StrOpt('v3_endpoint_type',
+               default='adminURL',
+               choices=['public', 'admin', 'internal',
+                        'publicURL', 'adminURL', 'internalURL'],
+               help="The endpoint type to use for OpenStack Identity "
+                    "(Keystone) API v3",
+               deprecated_opts=[cfg.DeprecatedOpt('endpoint_type',
+                                                  group='identity')]),
     cfg.StrOpt('username',
                help="Username to use for Nova API requests."),
     cfg.StrOpt('tenant_name',
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 60bf7cb..24a73fc 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -1080,11 +1080,6 @@
                 port = self._create_port(network_id=net_id,
                                          client=net_client,
                                          **create_port_body)
-                # if port_vnic_type is set, ports in the passing
-                # create_kwargs will be override, which cause the
-                # inconsistence. Set the port_id according to network id
-                if net_id == self.network['id']:
-                    self.port_id = port.id
                 ports.append({'port': port.id})
             if ports:
                 create_kwargs['networks'] = ports
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index b31ba69..e676063 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -101,7 +101,6 @@
         self.servers = []
 
     def _setup_network_and_servers(self, **kwargs):
-        vnic_type = CONF.network.port_vnic_type
         boot_with_port = kwargs.pop('boot_with_port', False)
         self.security_group = \
             self._create_security_group(tenant_id=self.tenant_id)
@@ -109,9 +108,7 @@
         self.check_networks()
 
         self.port_id = None
-        # when vnic_type is set, ports will be created in create_server.
-        # So no need to create a port here in this case.
-        if boot_with_port and not vnic_type:
+        if boot_with_port:
             # create a port on the network and boot with that
             self.port_id = self._create_port(self.network['id']).id
 
diff --git a/tempest/scenario/test_network_v6.py b/tempest/scenario/test_network_v6.py
index fba839a..9481e58 100644
--- a/tempest/scenario/test_network_v6.py
+++ b/tempest/scenario/test_network_v6.py
@@ -27,13 +27,17 @@
 
 
 class TestGettingAddress(manager.NetworkScenarioTest):
-    """Create network with subnets: one IPv4 and
-    one or few IPv6 in a given address mode
-    Boot 2 VMs on this network
-    Allocate and assign 2 FIP4
-    Check that vNICs of all VMs gets all addresses actually assigned
-    Ping4 to one VM from another one
-    If ping6 available in VM, do ping6 to all v6 addresses
+    """Test Summary:
+
+    1. Create network with subnets:
+        1.1. one IPv4 and
+        1.2. one or more IPv6 in a given address mode
+    2. Boot 2 VMs on this network
+    3. Allocate and assign 2 FIP4
+    4. Check that vNICs of all VMs gets all addresses actually assigned
+    5. Each VM will ping the other's v4 private address
+    6. If ping6 available in VM, each VM will ping all of the other's  v6
+       addresses as well as the router's
     """
 
     @classmethod
@@ -74,12 +78,13 @@
         self.network = self._create_network(tenant_id=self.tenant_id)
         sub4 = self._create_subnet(network=self.network,
                                    namestart='sub4',
-                                   ip_version=4,)
+                                   ip_version=4)
 
         router = self._get_router(tenant_id=self.tenant_id)
         sub4.add_to_router(router_id=router['id'])
         self.addCleanup(sub4.delete)
 
+        self.subnets_v6 = []
         for _ in range(n_subnets6):
             sub6 = self._create_subnet(network=self.network,
                                        namestart='sub6',
@@ -89,6 +94,7 @@
 
             sub6.add_to_router(router_id=router['id'])
             self.addCleanup(sub6.delete)
+            self.subnets_v6.append(sub6)
 
     @staticmethod
     def define_server_ips(srv):
@@ -145,23 +151,32 @@
             self.assertTrue(test.call_until_true(srv2_v6_addr_assigned,
                                                  CONF.compute.ping_timeout, 1))
 
-        result = sshv4_1.ping_host(ips_from_api_2['4'])
-        self.assertIn('0% packet loss', result)
-        result = sshv4_2.ping_host(ips_from_api_1['4'])
-        self.assertIn('0% packet loss', result)
+        self._check_connectivity(sshv4_1, ips_from_api_2['4'])
+        self._check_connectivity(sshv4_2, ips_from_api_1['4'])
 
         # Some VM (like cirros) may not have ping6 utility
         result = sshv4_1.exec_command('whereis ping6')
         is_ping6 = False if result == 'ping6:\n' else True
         if is_ping6:
             for i in range(n_subnets6):
-                result = sshv4_1.ping_host(ips_from_api_2['6'][i])
-                self.assertIn('0% packet loss', result)
-                result = sshv4_2.ping_host(ips_from_api_1['6'][i])
-                self.assertIn('0% packet loss', result)
+                self._check_connectivity(sshv4_1,
+                                         ips_from_api_2['6'][i])
+                self._check_connectivity(sshv4_1,
+                                         self.subnets_v6[i].gateway_ip)
+                self._check_connectivity(sshv4_2,
+                                         ips_from_api_1['6'][i])
+                self._check_connectivity(sshv4_2,
+                                         self.subnets_v6[i].gateway_ip)
         else:
             LOG.warning('Ping6 is not available, skipping')
 
+    def _check_connectivity(self, source, dest):
+        self.assertTrue(
+            self._check_remote_connectivity(source, dest),
+            "Timed out waiting for %s to become reachable from %s" %
+            (dest, source.ssh_client.host)
+        )
+
     @test.idempotent_id('2c92df61-29f0-4eaa-bee3-7c65bef62a43')
     @test.services('compute', 'network')
     def test_slaac_from_os(self):
diff --git a/tempest/services/identity/v2/json/identity_client.py b/tempest/services/identity/v2/json/identity_client.py
index 1076fca..c9345e0 100644
--- a/tempest/services/identity/v2/json/identity_client.py
+++ b/tempest/services/identity/v2/json/identity_client.py
@@ -259,6 +259,33 @@
         self.expected_success(204, resp.status)
         return service_client.ResponseBody(resp, body)
 
+    def create_endpoint(self, service_id, region_id, **kwargs):
+        """Create an endpoint for service."""
+        post_body = {
+            'service_id': service_id,
+            'region': region_id,
+            'publicurl': kwargs.get('publicurl'),
+            'adminurl': kwargs.get('adminurl'),
+            'internalurl': kwargs.get('internalurl')
+        }
+        post_body = json.dumps({'endpoint': post_body})
+        resp, body = self.post('/endpoints', post_body)
+        self.expected_success(200, resp.status)
+        return service_client.ResponseBody(resp, self._parse_resp(body))
+
+    def list_endpoints(self):
+        """List Endpoints - Returns Endpoints."""
+        resp, body = self.get('/endpoints')
+        self.expected_success(200, resp.status)
+        return service_client.ResponseBodyList(resp, self._parse_resp(body))
+
+    def delete_endpoint(self, endpoint_id):
+        """Delete an endpoint."""
+        url = '/endpoints/%s' % endpoint_id
+        resp, body = self.delete(url)
+        self.expected_success(204, resp.status)
+        return service_client.ResponseBody(resp, body)
+
     def update_user_password(self, user_id, new_pass):
         """Update User Password."""
         put_body = {
diff --git a/tempest/tests/services/compute/test_aggregates_client.py b/tempest/tests/services/compute/test_aggregates_client.py
index 9fe4544..eacc251 100644
--- a/tempest/tests/services/compute/test_aggregates_client.py
+++ b/tempest/tests/services/compute/test_aggregates_client.py
@@ -14,6 +14,7 @@
 
 import httplib2
 
+from oslo_serialization import jsonutils as json
 from oslotest import mockpatch
 
 from tempest.services.compute.json import aggregates_client
@@ -45,3 +46,92 @@
 
     def test_list_aggregates_with_bytes_body(self):
         self._test_list_aggregates(bytes_body=True)
+
+    def _test_show_aggregate(self, bytes_body=False):
+        expected = {"name": "hoge",
+                    "availability_zone": None,
+                    "deleted": False,
+                    "created_at":
+                    "2015-07-16T03:07:32.000000",
+                    "updated_at": None,
+                    "hosts": [],
+                    "deleted_at": None,
+                    "id": 1,
+                    "metadata": {}}
+        serialized_body = json.dumps({"aggregate": expected})
+        if bytes_body:
+            serialized_body = serialized_body.encode('utf-8')
+
+        mocked_resp = (httplib2.Response({'status': 200}), serialized_body)
+        self.useFixture(mockpatch.Patch(
+            'tempest.common.service_client.ServiceClient.get',
+            return_value=mocked_resp))
+        resp = self.client.show_aggregate(1)
+        self.assertEqual(expected, resp)
+
+    def test_show_aggregate_with_str_body(self):
+        self._test_show_aggregate()
+
+    def test_show_aggregate_with_bytes_body(self):
+        self._test_show_aggregate(bytes_body=True)
+
+    def _test_create_aggregate(self, bytes_body=False):
+        expected = {"name": u'\xf4',
+                    "availability_zone": None,
+                    "deleted": False,
+                    "created_at": "2015-07-21T04:11:18.000000",
+                    "updated_at": None,
+                    "deleted_at": None,
+                    "id": 1}
+        serialized_body = json.dumps({"aggregate": expected})
+        if bytes_body:
+            serialized_body = serialized_body.encode('utf-8')
+
+        mocked_resp = (httplib2.Response({'status': 200}), serialized_body)
+        self.useFixture(mockpatch.Patch(
+            'tempest.common.service_client.ServiceClient.post',
+            return_value=mocked_resp))
+        resp = self.client.create_aggregate(name='hoge')
+        self.assertEqual(expected, resp)
+
+    def test_create_aggregate_with_str_body(self):
+        self._test_create_aggregate()
+
+    def test_create_aggregate_with_bytes_body(self):
+        self._test_create_aggregate(bytes_body=True)
+
+    def test_delete_aggregate(self):
+        expected = {}
+        mocked_resp = (httplib2.Response({'status': 200}), None)
+        self.useFixture(mockpatch.Patch(
+            'tempest.common.service_client.ServiceClient.delete',
+            return_value=mocked_resp))
+        resp = self.client.delete_aggregate("1")
+        self.assertEqual(expected, resp)
+
+    def _test_update_aggregate(self, bytes_body=False):
+        expected = {"name": u'\xe9',
+                    "availability_zone": None,
+                    "deleted": False,
+                    "created_at": "2015-07-16T03:07:32.000000",
+                    "updated_at": "2015-07-23T05:16:29.000000",
+                    "hosts": [],
+                    "deleted_at": None,
+                    "id": 1,
+                    "metadata": {}}
+        serialized_body = json.dumps({"aggregate": expected})
+        if bytes_body:
+            serialized_body = serialized_body.encode('utf-8')
+
+        mocked_resp = (httplib2.Response({'status': 200}), serialized_body)
+        self.useFixture(mockpatch.Patch(
+            'tempest.common.service_client.ServiceClient.put',
+            return_value=mocked_resp))
+        resp = self.client.update_aggregate(1)
+        self.assertEqual(expected, resp)
+
+    def test_update_aggregate_with_str_body(self):
+        self._test_update_aggregate()
+
+    def test_update_aggregate_with_bytes_body(self):
+        self._test_update_aggregate(bytes_body=True)
diff --git a/tempest/tests/services/compute/test_limits_client.py b/tempest/tests/services/compute/test_limits_client.py
new file mode 100644
index 0000000..4086210
--- /dev/null
+++ b/tempest/tests/services/compute/test_limits_client.py
@@ -0,0 +1,69 @@
+# Copyright 2015 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.
+
+import httplib2
+
+from oslo_serialization import jsonutils as json
+from oslotest import mockpatch
+
+from tempest.services.compute.json import limits_client
+from tempest.tests import base
+from tempest.tests import fake_auth_provider
+
+
+class TestLimitsClient(base.TestCase):
+
+    def setUp(self):
+        super(TestLimitsClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = limits_client.LimitsClient(
+            fake_auth, 'compute', 'regionOne')
+
+    def _test_show_limits(self, bytes_body=False):
+        expected = {"rate": [],
+                    "absolute": {"maxServerMeta": 128,
+                                 "maxPersonality": 5,
+                                 "totalServerGroupsUsed": 0,
+                                 "maxImageMeta": 128,
+                                 "maxPersonalitySize": 10240,
+                                 "maxServerGroups": 10,
+                                 "maxSecurityGroupRules": 20,
+                                 "maxTotalKeypairs": 100,
+                                 "totalCoresUsed": 0,
+                                 "totalRAMUsed": 0,
+                                 "totalInstancesUsed": 0,
+                                 "maxSecurityGroups": 10,
+                                 "totalFloatingIpsUsed": 0,
+                                 "maxTotalCores": 20,
+                                 "totalSecurityGroupsUsed": 0,
+                                 "maxTotalFloatingIps": 10,
+                                 "maxTotalInstances": 10,
+                                 "maxTotalRAMSize": 51200,
+                                 "maxServerGroupMembers": 10}}
+        serialized_body = json.dumps({"limits": expected})
+        if bytes_body:
+            serialized_body = serialized_body.encode('utf-8')
+
+        mocked_resp = (httplib2.Response({'status': 200}), serialized_body)
+        self.useFixture(mockpatch.Patch(
+            'tempest.common.service_client.ServiceClient.get',
+            return_value=mocked_resp))
+        resp = self.client.show_limits()
+        self.assertEqual(expected, resp)
+
+    def test_show_limits_with_str_body(self):
+        self._test_show_limits()
+
+    def test_show_limits_with_bytes_body(self):
+        self._test_show_limits(bytes_body=True)
diff --git a/tempest/thirdparty/boto/test.py b/tempest/thirdparty/boto/test.py
index 1ff4dee..9f119b4 100644
--- a/tempest/thirdparty/boto/test.py
+++ b/tempest/thirdparty/boto/test.py
@@ -505,7 +505,7 @@
             LOG.critical("%s Volume has %s snapshot(s)", volume.id,
                          map(snaps.id, snaps))
 
-        # NOTE(afazekas): detaching/attching not valid EC2 status
+        # NOTE(afazekas): detaching/attaching not valid EC2 status
         def _volume_state():
             volume.update(validate=True)
             try:
diff --git a/test-requirements.txt b/test-requirements.txt
index 2ea30ec..db2b2ce 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -9,4 +9,4 @@
 mox>=0.5.3
 mock>=1.2
 coverage>=3.6
-oslotest>=1.9.0 # Apache-2.0
+oslotest>=1.10.0 # Apache-2.0