<NME> test_services.py
<BEF> # vim: tabstop=4 shiftwidth=4 softtabstop=4

# Copyright 2013 NEC Corporation
# All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#
#         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.lib import decorators


class ServicesAdminTestJSON(base.BaseV2ComputeAdminTest):
    """Tests Nova Services API.

    List and Enable/Disable require admin privileges.
    """

    @classmethod
    def setup_clients(cls):
        super(ServicesAdminTestJSON, cls).setup_clients()
        cls.client = cls.os_admin.services_client

    @decorators.idempotent_id('5be41ef4-53d1-41cc-8839-5c2a48a1b283')
    def test_list_services(self):
        """Listing nova services"""
        services = self.client.list_services()['services']
        self.assertNotEmpty(services)

    @attr(type='gate')
    def test_list_services(self):
        # List Compute services
        resp, services = self.client.list_services()
        self.assertEqual(200, resp.status)
        self.assertTrue(len(services) >= 2)

    @attr(type=['negative', 'gate'])
    def test_list_services_with_non_admin_user(self):
        # List Compute service with non admin user
        self.assertRaises(exceptions.Unauthorized,
                          self.non_admin_client.list_services)


class ServicesAdminTestXML(ServicesAdminTestJSON):
    _interface = 'xml'

<MSG> Merge "add service tests"
<DFF> @@ -1,6 +1,7 @@
 # vim: tabstop=4 shiftwidth=4 softtabstop=4
 
 # Copyright 2013 NEC Corporation
+# Copyright 2013 IBM Corp.
 # All Rights Reserved.
 #
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -36,17 +37,91 @@ class ServicesAdminTestJSON(base.BaseComputeAdminTest):
 
     @attr(type='gate')
     def test_list_services(self):
-        # List Compute services
         resp, services = self.client.list_services()
         self.assertEqual(200, resp.status)
-        self.assertTrue(len(services) >= 2)
+        self.assertNotEqual(0, len(services))
 
     @attr(type=['negative', 'gate'])
     def test_list_services_with_non_admin_user(self):
-        # List Compute service with non admin user
         self.assertRaises(exceptions.Unauthorized,
                           self.non_admin_client.list_services)
 
+    @attr(type='gate')
+    def test_get_service_by_service_binary_name(self):
+        binary_name = 'nova-compute'
+        params = {'binary': binary_name}
+        resp, services = self.client.list_services(params)
+        self.assertEqual(200, resp.status)
+        self.assertNotEqual(0, len(services))
+        for service in services:
+            self.assertEqual(binary_name, service['binary'])
+
+    @attr(type='gate')
+    def test_get_service_by_host_name(self):
+        resp, services = self.client.list_services()
+        host_name = services[0]['host']
+        services_on_host = [service for service in services if
+                            service['host'] == host_name]
+        params = {'host': host_name}
+        resp, services = self.client.list_services(params)
+        self.assertEqual(services_on_host, services)
+
+    @attr(type=['negative', 'gate'])
+    def test_get_service_by_invalid_params(self):
+        #return all services if send the request with invalid parameter
+        resp, services = self.client.list_services()
+        params = {'xxx': 'nova-compute'}
+        resp, services_xxx = self.client.list_services(params)
+        self.assertEqual(200, resp.status)
+        self.assertEqual(len(services), len(services_xxx))
+
+    @attr(type='gate')
+    def test_get_service_by_service_and_host_name(self):
+        resp, services = self.client.list_services()
+        host_name = services[0]['host']
+        binary_name = services[0]['binary']
+        params = {'host': host_name, 'binary': binary_name}
+        resp, services = self.client.list_services(params)
+        self.assertEqual(200, resp.status)
+        self.assertEqual(1, len(services))
+        self.assertEqual(host_name, services[0]['host'])
+        self.assertEqual(binary_name, services[0]['binary'])
+
+    @attr(type=['negative', 'gate'])
+    def test_get_service_by_invalid_service_and_valid_host(self):
+        resp, services = self.client.list_services()
+        host_name = services[0]['host']
+        params = {'host': host_name, 'binary': 'xxx'}
+        resp, services = self.client.list_services(params)
+        self.assertEqual(200, resp.status)
+        self.assertEqual(0, len(services))
+
+    @attr(type=['negative', 'gate'])
+    def test_get_service_with_valid_service_and_invalid_host(self):
+        resp, services = self.client.list_services()
+        binary_name = services[0]['binary']
+        params = {'host': 'xxx', 'binary': binary_name}
+        resp, services = self.client.list_services(params)
+        self.assertEqual(200, resp.status)
+        self.assertEqual(0, len(services))
+
+    @attr(type='gate')
+    def test_service_enable_disable(self):
+        resp, services = self.client.list_services()
+        host_name = services[0]['host']
+        binary_name = services[0]['binary']
+
+        resp, service = self.client.disable_service(host_name, binary_name)
+        self.assertEqual(200, resp.status)
+        params = {'host': host_name, 'binary': binary_name}
+        resp, services = self.client.list_services(params)
+        self.assertEqual('disabled', services[0]['status'])
+
+        resp, service = self.client.enable_service(host_name, binary_name)
+        self.assertEqual(200, resp.status)
+        resp, services = self.client.list_services(params)
+        self.assertEqual('enabled', services[0]['status'])
+
 
 class ServicesAdminTestXML(ServicesAdminTestJSON):
     _interface = 'xml'

{'commit': 'diff --git a/tempest/api/compute/admin/test_services.py b/tempest/api/compute/admin/test_services.py\nindex 78dac2135..3b3c6ce6d 100644\n--- a/tempest/api/compute/admin/test_services.py\n+++ b/tempest/api/compute/admin/test_services.py\n@@ -1,6 +1,7 @@\n # vim: tabstop=4 shiftwidth=4 softtabstop=4\n \n # Copyright 2013 NEC Corporation\n+# Copyright 2013 IBM Corp.\n # All Rights Reserved.\n #\n #    Licensed under the Apache License, Version 2.0 (the "License"); you may\n@@ -36,17 +37,91 @@ class ServicesAdminTestJSON(base.BaseComputeAdminTest):\n \n     @attr(type=\'gate\')\n     def test_list_services(self):\n-        # List Compute services\n         resp, services = self.client.list_services()\n         self.assertEqual(200, resp.status)\n-        self.assertTrue(len(services) >= 2)\n+        self.assertNotEqual(0, len(services))\n \n     @attr(type=[\'negative\', \'gate\'])\n     def test_list_services_with_non_admin_user(self):\n-        # List Compute service with non admin user\n         self.assertRaises(exceptions.Unauthorized,\n                           self.non_admin_client.list_services)\n \n+    @attr(type=\'gate\')\n+    def test_get_service_by_service_binary_name(self):\n+        binary_name = \'nova-compute\'\n+        params = {\'binary\': binary_name}\n+        resp, services = self.client.list_services(params)\n+        self.assertEqual(200, resp.status)\n+        self.assertNotEqual(0, len(services))\n+        for service in services:\n+            self.assertEqual(binary_name, service[\'binary\'])\n+\n+    @attr(type=\'gate\')\n+    def test_get_service_by_host_name(self):\n+        resp, services = self.client.list_services()\n+        host_name = services[0][\'host\']\n+        services_on_host = [service for service in services if\n+                            service[\'host\'] == host_name]\n+        params = {\'host\': host_name}\n+        resp, services = self.client.list_services(params)\n+        self.assertEqual(services_on_host, services)\n+\n+    @attr(type=[\'negative\', \'gate\'])\n+    def test_get_service_by_invalid_params(self):\n+        #return all services if send the request with invalid parameter\n+        resp, services = self.client.list_services()\n+        params = {\'xxx\': \'nova-compute\'}\n+        resp, services_xxx = self.client.list_services(params)\n+        self.assertEqual(200, resp.status)\n+        self.assertEqual(len(services), len(services_xxx))\n+\n+    @attr(type=\'gate\')\n+    def test_get_service_by_service_and_host_name(self):\n+        resp, services = self.client.list_services()\n+        host_name = services[0][\'host\']\n+        binary_name = services[0][\'binary\']\n+        params = {\'host\': host_name, \'binary\': binary_name}\n+        resp, services = self.client.list_services(params)\n+        self.assertEqual(200, resp.status)\n+        self.assertEqual(1, len(services))\n+        self.assertEqual(host_name, services[0][\'host\'])\n+        self.assertEqual(binary_name, services[0][\'binary\'])\n+\n+    @attr(type=[\'negative\', \'gate\'])\n+    def test_get_service_by_invalid_service_and_valid_host(self):\n+        resp, services = self.client.list_services()\n+        host_name = services[0][\'host\']\n+        params = {\'host\': host_name, \'binary\': \'xxx\'}\n+        resp, services = self.client.list_services(params)\n+        self.assertEqual(200, resp.status)\n+        self.assertEqual(0, len(services))\n+\n+    @attr(type=[\'negative\', \'gate\'])\n+    def test_get_service_with_valid_service_and_invalid_host(self):\n+        resp, services = self.client.list_services()\n+        binary_name = services[0][\'binary\']\n+        params = {\'host\': \'xxx\', \'binary\': binary_name}\n+        resp, services = self.client.list_services(params)\n+        self.assertEqual(200, resp.status)\n+        self.assertEqual(0, len(services))\n+\n+    @attr(type=\'gate\')\n+    def test_service_enable_disable(self):\n+        resp, services = self.client.list_services()\n+        host_name = services[0][\'host\']\n+        binary_name = services[0][\'binary\']\n+\n+        resp, service = self.client.disable_service(host_name, binary_name)\n+        self.assertEqual(200, resp.status)\n+        params = {\'host\': host_name, \'binary\': binary_name}\n+        resp, services = self.client.list_services(params)\n+        self.assertEqual(\'disabled\', services[0][\'status\'])\n+\n+        resp, service = self.client.enable_service(host_name, binary_name)\n+        self.assertEqual(200, resp.status)\n+        resp, services = self.client.list_services(params)\n+        self.assertEqual(\'enabled\', services[0][\'status\'])\n+\n \n class ServicesAdminTestXML(ServicesAdminTestJSON):\n     _interface = \'xml\'\ndiff --git a/tempest/services/compute/json/services_client.py b/tempest/services/compute/json/services_client.py\nindex d054f72e0..4db75962b 100644\n--- a/tempest/services/compute/json/services_client.py\n+++ b/tempest/services/compute/json/services_client.py\n@@ -1,6 +1,7 @@\n # vim: tabstop=4 shiftwidth=4 softtabstop=4\n \n # Copyright 2013 NEC Corporation\n+# Copyright 2013 IBM Corp.\n # All Rights Reserved.\n #\n #    Licensed under the Apache License, Version 2.0 (the "License"); you may\n@@ -16,6 +17,7 @@\n #    under the License.\n \n import json\n+import urllib\n \n from tempest.common.rest_client import RestClient\n \n@@ -27,7 +29,33 @@ class ServicesClientJSON(RestClient):\n                                                  auth_url, tenant_name)\n         self.service = self.config.compute.catalog_type\n \n-    def list_services(self):\n-        resp, body = self.get("os-services")\n+    def list_services(self, params=None):\n+        url = \'os-services\'\n+        if params:\n+            url += \'?%s\' % urllib.urlencode(params)\n+\n+        resp, body = self.get(url)\n         body = json.loads(body)\n         return resp, body[\'services\']\n+\n+    def enable_service(self, host_name, binary):\n+        """\n+        Enable service on a host\n+        host_name: Name of host\n+        binary: Service binary\n+        """\n+        post_body = json.dumps({\'binary\': binary, \'host\': host_name})\n+        resp, body = self.put(\'os-services/enable\', post_body, self.headers)\n+        body = json.loads(body)\n+        return resp, body[\'service\']\n+\n+    def disable_service(self, host_name, binary):\n+        """\n+        Disable service on a host\n+        host_name: Name of host\n+        binary: Service binary\n+        """\n+        post_body = json.dumps({\'binary\': binary, \'host\': host_name})\n+        resp, body = self.put(\'os-services/disable\', post_body, self.headers)\n+        body = json.loads(body)\n+        return resp, body[\'service\']\ndiff --git a/tempest/services/compute/xml/services_client.py b/tempest/services/compute/xml/services_client.py\nindex ce2340312..ac304e2b2 100644\n--- a/tempest/services/compute/xml/services_client.py\n+++ b/tempest/services/compute/xml/services_client.py\n@@ -1,6 +1,7 @@\n # vim: tabstop=4 shiftwidth=4 softtabstop=4\n \n # Copyright 2013 NEC Corporation\n+# Copyright 2013 IBM Corp.\n # All Rights Reserved.\n #\n #    Licensed under the Apache License, Version 2.0 (the "License"); you may\n@@ -15,8 +16,12 @@\n #    License for the specific language governing permissions and limitations\n #    under the License.\n \n+import urllib\n+\n from lxml import etree\n from tempest.common.rest_client import RestClientXML\n+from tempest.services.compute.xml.common import Document\n+from tempest.services.compute.xml.common import Element\n from tempest.services.compute.xml.common import xml_to_json\n \n \n@@ -27,8 +32,42 @@ class ServicesClientXML(RestClientXML):\n                                                 auth_url, tenant_name)\n         self.service = self.config.compute.catalog_type\n \n-    def list_services(self):\n-        resp, body = self.get("os-services", self.headers)\n+    def list_services(self, params=None):\n+        url = \'os-services\'\n+        if params:\n+            url += \'?%s\' % urllib.urlencode(params)\n+\n+        resp, body = self.get(url, self.headers)\n         node = etree.fromstring(body)\n         body = [xml_to_json(x) for x in node.getchildren()]\n         return resp, body\n+\n+    def enable_service(self, host_name, binary):\n+        """\n+        Enable service on a host\n+        host_name: Name of host\n+        binary: Service binary\n+        """\n+        post_body = Element("service")\n+        post_body.add_attr(\'binary\', binary)\n+        post_body.add_attr(\'host\', host_name)\n+\n+        resp, body = self.put(\'os-services/enable\', str(Document(post_body)),\n+                              self.headers)\n+        body = xml_to_json(etree.fromstring(body))\n+        return resp, body\n+\n+    def disable_service(self, host_name, binary):\n+        """\n+        Disable service on a host\n+        host_name: Name of host\n+        binary: Service binary\n+        """\n+        post_body = Element("service")\n+        post_body.add_attr(\'binary\', binary)\n+        post_body.add_attr(\'host\', host_name)\n+\n+        resp, body = self.put(\'os-services/disable\', str(Document(post_body)),\n+                              self.headers)\n+        body = xml_to_json(etree.fromstring(body))\n+        return resp, body\n', 'commit_subject': 'Merge "add service tests"', 'repo_name': 'openstack/tempest', 'committer': {'name': 'Gerrit Code Review', 'email': '61e62b213a1a56f7695845df4fc372a10cb0a73e@openstack.org', 'time_sec': '1374842050', 'tz_offset': '0', 'date': {'seconds': '1374842050'}}, 'commit_tree': 'a2f48075d5359f9d02eaf52df258611d11e45d9e', 'commit_message': 'Merge "add service tests"', 'language_name': 'Shell', 'license': 'apache-2.0', 'hunks': '@@ -1,6 +1,7 @@\n # vim: tabstop=4 shiftwidth=4 softtabstop=4\n \n # Copyright 2013 NEC Corporation\n+# Copyright 2013 IBM Corp.\n # All Rights Reserved.\n #\n #    Licensed under the Apache License, Version 2.0 (the "License"); you may\n@@ -36,17 +37,91 @@ class ServicesAdminTestJSON(base.BaseComputeAdminTest):\n \n     @attr(type=\'gate\')\n     def test_list_services(self):\n-        # List Compute services\n         resp, services = self.client.list_services()\n         self.assertEqual(200, resp.status)\n-        self.assertTrue(len(services) >= 2)\n+        self.assertNotEqual(0, len(services))\n \n     @attr(type=[\'negative\', \'gate\'])\n     def test_list_services_with_non_admin_user(self):\n-        # List Compute service with non admin user\n         self.assertRaises(exceptions.Unauthorized,\n                           self.non_admin_client.list_services)\n \n+    @attr(type=\'gate\')\n+    def test_get_service_by_service_binary_name(self):\n+        binary_name = \'nova-compute\'\n+        params = {\'binary\': binary_name}\n+        resp, services = self.client.list_services(params)\n+        self.assertEqual(200, resp.status)\n+        self.assertNotEqual(0, len(services))\n+        for service in services:\n+            self.assertEqual(binary_name, service[\'binary\'])\n+\n+    @attr(type=\'gate\')\n+    def test_get_service_by_host_name(self):\n+        resp, services = self.client.list_services()\n+        host_name = services[0][\'host\']\n+        services_on_host = [service for service in services if\n+                            service[\'host\'] == host_name]\n+        params = {\'host\': host_name}\n+        resp, services = self.client.list_services(params)\n+        self.assertEqual(services_on_host, services)\n+\n+    @attr(type=[\'negative\', \'gate\'])\n+    def test_get_service_by_invalid_params(self):\n+        #return all services if send the request with invalid parameter\n+        resp, services = self.client.list_services()\n+        params = {\'xxx\': \'nova-compute\'}\n+        resp, services_xxx = self.client.list_services(params)\n+        self.assertEqual(200, resp.status)\n+        self.assertEqual(len(services), len(services_xxx))\n+\n+    @attr(type=\'gate\')\n+    def test_get_service_by_service_and_host_name(self):\n+        resp, services = self.client.list_services()\n+        host_name = services[0][\'host\']\n+        binary_name = services[0][\'binary\']\n+        params = {\'host\': host_name, \'binary\': binary_name}\n+        resp, services = self.client.list_services(params)\n+        self.assertEqual(200, resp.status)\n+        self.assertEqual(1, len(services))\n+        self.assertEqual(host_name, services[0][\'host\'])\n+        self.assertEqual(binary_name, services[0][\'binary\'])\n+\n+    @attr(type=[\'negative\', \'gate\'])\n+    def test_get_service_by_invalid_service_and_valid_host(self):\n+        resp, services = self.client.list_services()\n+        host_name = services[0][\'host\']\n+        params = {\'host\': host_name, \'binary\': \'xxx\'}\n+        resp, services = self.client.list_services(params)\n+        self.assertEqual(200, resp.status)\n+        self.assertEqual(0, len(services))\n+\n+    @attr(type=[\'negative\', \'gate\'])\n+    def test_get_service_with_valid_service_and_invalid_host(self):\n+        resp, services = self.client.list_services()\n+        binary_name = services[0][\'binary\']\n+        params = {\'host\': \'xxx\', \'binary\': binary_name}\n+        resp, services = self.client.list_services(params)\n+        self.assertEqual(200, resp.status)\n+        self.assertEqual(0, len(services))\n+\n+    @attr(type=\'gate\')\n+    def test_service_enable_disable(self):\n+        resp, services = self.client.list_services()\n+        host_name = services[0][\'host\']\n+        binary_name = services[0][\'binary\']\n+\n+        resp, service = self.client.disable_service(host_name, binary_name)\n+        self.assertEqual(200, resp.status)\n+        params = {\'host\': host_name, \'binary\': binary_name}\n+        resp, services = self.client.list_services(params)\n+        self.assertEqual(\'disabled\', services[0][\'status\'])\n+\n+        resp, service = self.client.enable_service(host_name, binary_name)\n+        self.assertEqual(200, resp.status)\n+        resp, services = self.client.list_services(params)\n+        self.assertEqual(\'enabled\', services[0][\'status\'])\n+\n \n class ServicesAdminTestXML(ServicesAdminTestJSON):\n     _interface = \'xml\'\n', 'addition_count': 78, 'deletion_count': 3, 'src_file': 'a/tempest/api/compute/admin/test_services.py', 'tgt_file': 'b/tempest/api/compute/admin/test_services.py', 'file_extension': '.py', 'before_file': '# vim: tabstop=4 shiftwidth=4 softtabstop=4\n\n# Copyright 2013 NEC Corporation\n# All Rights Reserved.\n#\n#    Licensed under the Apache License, Version 2.0 (the "License"); you may\n#\n#         http://www.apache.org/licenses/LICENSE-2.0\n#\n#    Unless required by applicable law or agreed to in writing, software\n#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n#    License for the specific language governing permissions and limitations\n#    under the License.\n\nfrom tempest.api.compute import base\nfrom tempest.lib import decorators\n\n\nclass ServicesAdminTestJSON(base.BaseV2ComputeAdminTest):\n    """Tests Nova Services API.\n\n    List and Enable/Disable require admin privileges.\n    """\n\n    @classmethod\n    def setup_clients(cls):\n        super(ServicesAdminTestJSON, cls).setup_clients()\n        cls.client = cls.os_admin.services_client\n\n    @decorators.idempotent_id(\'5be41ef4-53d1-41cc-8839-5c2a48a1b283\')\n    def test_list_services(self):\n        """Listing nova services"""\n        services = self.client.list_services()[\'services\']\n        self.assertNotEmpty(services)\n\n    @attr(type=\'gate\')\n    def test_list_services(self):\n        # List Compute services\n        resp, services = self.client.list_services()\n        self.assertEqual(200, resp.status)\n        self.assertTrue(len(services) >= 2)\n\n    @attr(type=[\'negative\', \'gate\'])\n    def test_list_services_with_non_admin_user(self):\n        # List Compute service with non admin user\n        self.assertRaises(exceptions.Unauthorized,\n                          self.non_admin_client.list_services)\n\n\nclass ServicesAdminTestXML(ServicesAdminTestJSON):\n    _interface = \'xml\'\n', 'message': 'Merge "add service tests"', 'author_name': 'Gerrit Code Review', 'lang': 'py'}