Merge "Use min_count to create servers in ListServersNegativeTestJSON"
diff --git a/releasenotes/notes/add-show-host-to-hosts-client-library-c60c4eb49d139480.yaml b/releasenotes/notes/add-show-host-to-hosts-client-library-c60c4eb49d139480.yaml
new file mode 100644
index 0000000..0de1803
--- /dev/null
+++ b/releasenotes/notes/add-show-host-to-hosts-client-library-c60c4eb49d139480.yaml
@@ -0,0 +1,5 @@
+---
+features:
+  - |
+    Add show host API to the volume v2 hosts_client library.
+    This feature enables the possibility to show details for a host.
diff --git a/tempest/api/compute/images/test_images_oneserver.py b/tempest/api/compute/images/test_images_oneserver.py
index db24174..83447b6 100644
--- a/tempest/api/compute/images/test_images_oneserver.py
+++ b/tempest/api/compute/images/test_images_oneserver.py
@@ -24,6 +24,11 @@
 class ImagesOneServerTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
+    def resource_setup(cls):
+        super(ImagesOneServerTestJSON, cls).resource_setup()
+        cls.server_id = cls.create_test_server(wait_until='ACTIVE')['id']
+
+    @classmethod
     def skip_checks(cls):
         super(ImagesOneServerTestJSON, cls).skip_checks()
         if not CONF.service_available.glance:
@@ -46,12 +51,10 @@
 
     @decorators.idempotent_id('3731d080-d4c5-4872-b41a-64d0d0021314')
     def test_create_delete_image(self):
-        server_id = self.create_test_server(wait_until='ACTIVE')['id']
-
         # Create a new image
         name = data_utils.rand_name('image')
         meta = {'image_type': 'test'}
-        image = self.create_image_from_server(server_id, name=name,
+        image = self.create_image_from_server(self.server_id, name=name,
                                               metadata=meta,
                                               wait_until='ACTIVE')
 
@@ -76,8 +79,6 @@
 
     @decorators.idempotent_id('3b7c6fe4-dfe7-477c-9243-b06359db51e6')
     def test_create_image_specify_multibyte_character_image_name(self):
-        server_id = self.create_test_server(wait_until='ACTIVE')['id']
-
         # prefix character is:
         # http://www.fileformat.info/info/unicode/char/1F4A9/index.htm
 
@@ -85,6 +86,6 @@
         # #1370954 in glance which will 500 if mysql is used as the
         # backend and it attempts to store a 4 byte utf-8 character
         utf8_name = data_utils.rand_name(b'\xe2\x82\xa1'.decode('utf-8'))
-        body = self.client.create_image(server_id, name=utf8_name)
+        body = self.client.create_image(self.server_id, name=utf8_name)
         image_id = data_utils.parse_image_id(body.response['location'])
         self.addCleanup(self.client.delete_image, image_id)
diff --git a/tempest/api/volume/admin/test_volume_hosts.py b/tempest/api/volume/admin/test_volume_hosts.py
index 04d6cf9..e4ec442 100644
--- a/tempest/api/volume/admin/test_volume_hosts.py
+++ b/tempest/api/volume/admin/test_volume_hosts.py
@@ -13,6 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import random
+
 from tempest.api.volume import base
 from tempest.lib import decorators
 
@@ -22,5 +24,38 @@
     @decorators.idempotent_id('d5f3efa2-6684-4190-9ced-1c2f526352ad')
     def test_list_hosts(self):
         hosts = self.admin_hosts_client.list_hosts()['hosts']
-        self.assertGreaterEqual(len(hosts), 2, "No. of hosts are < 2,"
-                                "response of list hosts is: % s" % hosts)
+        self.assertGreaterEqual(len(hosts), 2,
+                                "The count of volume hosts is < 2, "
+                                "response of list hosts is: %s" % hosts)
+
+        # Check elements in volume hosts list
+        host_list_keys = ['service', 'host_name', 'last-update',
+                          'zone', 'service-status', 'service-state']
+        for host in hosts:
+            for key in host_list_keys:
+                self.assertIn(key, host)
+
+    @decorators.idempotent_id('21168d57-b373-4b71-a3ac-f2c88f0c5d31')
+    def test_show_host(self):
+        hosts = self.admin_hosts_client.list_hosts()['hosts']
+        self.assertGreaterEqual(len(hosts), 2,
+                                "The count of volume hosts is < 2, "
+                                "response of list hosts is: %s" % hosts)
+
+        # Note(jeremyZ): Host in volume is always presented in two formats:
+        # <host-name> or <host-name>@<driver-name>. Since Mitaka is EOL,
+        # both formats can be chosen for test.
+        host_names = [host['host_name'] for host in hosts]
+        self.assertNotEmpty(host_names, "No available volume host is found, "
+                                        "all hosts that found are: %s" % hosts)
+
+        # Choose a random host to get and check its elements
+        host_details = self.admin_hosts_client.show_host(
+            random.choice(host_names))['host']
+        self.assertNotEmpty(host_details)
+        host_detail_keys = ['project', 'volume_count', 'snapshot_count',
+                            'host', 'total_volume_gb', 'total_snapshot_gb']
+        for detail in host_details:
+            self.assertIn('resource', detail)
+            for key in host_detail_keys:
+                self.assertIn(key, detail['resource'])
diff --git a/tempest/lib/services/volume/v2/hosts_client.py b/tempest/lib/services/volume/v2/hosts_client.py
index dd7c482..8fcf4d0 100644
--- a/tempest/lib/services/volume/v2/hosts_client.py
+++ b/tempest/lib/services/volume/v2/hosts_client.py
@@ -34,3 +34,11 @@
         body = json.loads(body)
         self.expected_success(200, resp.status)
         return rest_client.ResponseBody(resp, body)
+
+    def show_host(self, host_name):
+        """Show host details."""
+        url = 'os-hosts/%s' % host_name
+        resp, body = self.get(url)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/tests/lib/services/volume/v2/test_hosts_client.py b/tempest/tests/lib/services/volume/v2/test_hosts_client.py
new file mode 100644
index 0000000..e107910
--- /dev/null
+++ b/tempest/tests/lib/services/volume/v2/test_hosts_client.py
@@ -0,0 +1,97 @@
+# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD
+# 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.lib.services.volume.v2 import hosts_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestQuotasClient(base.BaseServiceTest):
+    FAKE_LIST_HOSTS = {
+        "hosts": [
+            {
+                "service-status": "available",
+                "service": "cinder-scheduler",
+                "zone": "nova",
+                "service-state": "enabled",
+                "host_name": "fake-host",
+                "last-update": "2017-04-12T04:26:03.000000"
+            },
+            {
+                "service-status": "available",
+                "service": "cinder-volume",
+                "zone": "nova",
+                "service-state": "enabled",
+                "host_name": "fake-host@rbd",
+                "last-update": "2017-04-12T04:26:07.000000"
+            }
+        ]
+    }
+
+    FAKE_HOST_INFO = {
+        "host": [
+            {
+                "resource": {
+                    "volume_count": "2",
+                    "total_volume_gb": "2",
+                    "total_snapshot_gb": "0",
+                    "project": "(total)",
+                    "host": "fake-host",
+                    "snapshot_count": "0"
+                }
+            },
+            {
+                "resource": {
+                    "volume_count": "2",
+                    "total_volume_gb": "2",
+                    "total_snapshot_gb": "0",
+                    "project": "f21a9c86d7114bf99c711f4874d80474",
+                    "host": "fake-host",
+                    "snapshot_count": "0"
+                }
+            }
+        ]
+    }
+
+    def setUp(self):
+        super(TestQuotasClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.client = hosts_client.HostsClient(fake_auth,
+                                               'volume',
+                                               'regionOne')
+
+    def _test_list_hosts(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_hosts,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_LIST_HOSTS, bytes_body)
+
+    def _test_show_host(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_host,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_HOST_INFO, bytes_body, host_name='fake-host')
+
+    def test_list_hosts_with_str_body(self):
+        self._test_list_hosts()
+
+    def test_list_hosts_with_bytes_body(self):
+        self._test_list_hosts(bytes_body=True)
+
+    def test_show_host_with_str_body(self):
+        self._test_show_host()
+
+    def test_show_host_with_bytes_body(self):
+        self._test_show_host(bytes_body=True)