Merge "Addition of XML support to test_quotas.py"
diff --git a/tempest/clients.py b/tempest/clients.py
index 29e83bf..7a7ea13 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -32,7 +32,7 @@
 from tempest.services.compute.json.security_groups_client import \
     SecurityGroupsClientJSON
 from tempest.services.compute.json.keypairs_client import KeyPairsClientJSON
-from tempest.services.compute.json.quotas_client import QuotasClient
+from tempest.services.compute.json.quotas_client import QuotasClientJSON
 from tempest.services.compute.json.volumes_extensions_client import \
     VolumesExtensionsClientJSON
 from tempest.services.compute.json.console_output_client import \
@@ -44,6 +44,7 @@
 from tempest.services.compute.xml.images_client import ImagesClientXML
 from tempest.services.compute.xml.keypairs_client import KeyPairsClientXML
 from tempest.services.compute.xml.limits_client import LimitsClientXML
+from tempest.services.compute.xml.quotas_client import QuotasClientXML
 from tempest.services.compute.xml.security_groups_client \
     import SecurityGroupsClientXML
 from tempest.services.compute.xml.servers_client import ServersClientXML
@@ -79,6 +80,11 @@
     "xml": KeyPairsClientXML,
 }
 
+QUOTAS_CLIENTS = {
+    "json": QuotasClientJSON,
+    "xml": QuotasClientXML,
+}
+
 SERVERS_CLIENTS = {
     "json": ServersClientJSON,
     "xml": ServersClientXML,
@@ -180,6 +186,7 @@
             self.limits_client = LIMITS_CLIENTS[interface](*client_args)
             self.images_client = IMAGES_CLIENTS[interface](*client_args)
             self.keypairs_client = KEYPAIRS_CLIENTS[interface](*client_args)
+            self.quotas_client = QUOTAS_CLIENTS[interface](*client_args)
             self.flavors_client = FLAVORS_CLIENTS[interface](*client_args)
             ext_cli = EXTENSIONS_CLIENTS[interface](*client_args)
             self.extensions_client = ext_cli
@@ -196,7 +203,6 @@
         except KeyError:
             msg = "Unsupported interface type `%s'" % interface
             raise exceptions.InvalidConfiguration(msg)
-        self.quotas_client = QuotasClient(*client_args)
         self.network_client = NetworkClient(*client_args)
         self.account_client = AccountClient(*client_args)
         self.container_client = ContainerClient(*client_args)
diff --git a/tempest/manager.py b/tempest/manager.py
index 4137ec3..cb1e52d 100644
--- a/tempest/manager.py
+++ b/tempest/manager.py
@@ -55,7 +55,7 @@
 VolumesExtensionsClient = volumes_extensions_client.VolumesExtensionsClientJSON
 VolumesClient = volumes_client.VolumesClientJSON
 ConsoleOutputsClient = console_output_client.ConsoleOutputsClientJSON
-QuotasClient = quotas_client.QuotasClient
+QuotasClient = quotas_client.QuotasClientJSON
 
 LOG = logging.getLogger(__name__)
 
diff --git a/tempest/services/compute/admin/json/quotas_client.py b/tempest/services/compute/admin/json/quotas_client.py
index 625d4d4..0a4bd72 100644
--- a/tempest/services/compute/admin/json/quotas_client.py
+++ b/tempest/services/compute/admin/json/quotas_client.py
@@ -17,14 +17,14 @@
 
 import json
 
-from tempest.services.compute.json.quotas_client import QuotasClient
+from tempest.services.compute.json.quotas_client import QuotasClientJSON
 
 
-class AdminQuotasClient(QuotasClient):
+class AdminQuotasClientJSON(QuotasClientJSON):
 
     def __init__(self, config, username, password, auth_url, tenant_name=None):
-        super(AdminQuotasClient, self).__init__(config, username, password,
-                                                auth_url, tenant_name)
+        super(AdminQuotasClientJSON, self).__init__(config, username, password,
+                                                    auth_url, tenant_name)
 
     def update_quota_set(self, tenant_id, injected_file_content_bytes=None,
                          metadata_items=None, ram=None, floating_ips=None,
diff --git a/tempest/services/compute/admin/xml/__init__.py b/tempest/services/compute/admin/xml/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/services/compute/admin/xml/__init__.py
diff --git a/tempest/services/compute/admin/xml/quotas_client.py b/tempest/services/compute/admin/xml/quotas_client.py
new file mode 100644
index 0000000..d567a9c
--- /dev/null
+++ b/tempest/services/compute/admin/xml/quotas_client.py
@@ -0,0 +1,88 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2012 NTT Data
+# 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 urllib
+
+from lxml import etree
+
+from tempest.common.rest_client import RestClientXML
+from tempest.services.compute.xml.common import Document
+from tempest.services.compute.xml.common import Element
+from tempest.services.compute.xml.common import xml_to_json
+from tempest.services.compute.xml.common import XMLNS_11
+from tempest.services.compute.xml.quotas_client import QuotasClientXML
+
+
+class AdminQuotasClientXML(QuotasClientXML):
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(AdminQuotasClientXML, self).__init__(config, username, password,
+                                                   auth_url, tenant_name)
+
+    def update_quota_set(self, tenant_id, injected_file_content_bytes=None,
+                         metadata_items=None, ram=None, floating_ips=None,
+                         key_pairs=None, instances=None,
+                         security_group_rules=None, injected_files=None,
+                         cores=None, injected_file_path_bytes=None,
+                         security_groups=None):
+        """
+        Updates the tenant's quota limits for one or more resources
+        """
+        post_body = Element("quota_set",
+                            xmlns=XMLNS_11)
+
+        if injected_file_content_bytes is not None:
+            post_body.add_attr('injected_file_content_bytes',
+                               injected_file_content_bytes)
+
+        if metadata_items is not None:
+            post_body.add_attr('metadata_items', metadata_items)
+
+        if ram is not None:
+            post_body.add_attr('ram', ram)
+
+        if floating_ips is not None:
+            post_body.add_attr('floating_ips', floating_ips)
+
+        if key_pairs is not None:
+            post_body.add_attr('key_pairs', key_pairs)
+
+        if instances is not None:
+            post_body.add_attr('instances', instances)
+
+        if security_group_rules is not None:
+            post_body.add_attr('security_group_rules', security_group_rules)
+
+        if injected_files is not None:
+            post_body.add_attr('injected_files', injected_files)
+
+        if cores is not None:
+            post_body.add_attr('cores', cores)
+
+        if injected_file_path_bytes is not None:
+            post_body.add_attr('injected_file_path_bytes',
+                               injected_file_path_bytes)
+
+        if security_groups is not None:
+            post_body.add_attr('security_groups', security_groups)
+
+        resp, body = self.put('os-quota-sets/%s' % str(tenant_id),
+                              str(Document(post_body)),
+                              self.headers)
+        body = xml_to_json(etree.fromstring(body))
+        body = self._format_quota(body)
+        return resp, body
diff --git a/tempest/services/compute/json/quotas_client.py b/tempest/services/compute/json/quotas_client.py
index 543b015..a95ff1c 100644
--- a/tempest/services/compute/json/quotas_client.py
+++ b/tempest/services/compute/json/quotas_client.py
@@ -20,11 +20,11 @@
 from tempest.common.rest_client import RestClient
 
 
-class QuotasClient(RestClient):
+class QuotasClientJSON(RestClient):
 
     def __init__(self, config, username, password, auth_url, tenant_name=None):
-        super(QuotasClient, self).__init__(config, username, password,
-                                           auth_url, tenant_name)
+        super(QuotasClientJSON, self).__init__(config, username, password,
+                                               auth_url, tenant_name)
         self.service = self.config.compute.catalog_type
 
     def get_quota_set(self, tenant_id):
diff --git a/tempest/services/compute/xml/quotas_client.py b/tempest/services/compute/xml/quotas_client.py
new file mode 100644
index 0000000..8978214
--- /dev/null
+++ b/tempest/services/compute/xml/quotas_client.py
@@ -0,0 +1,58 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2012 NTT Data
+# 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 urllib
+
+from lxml import etree
+
+from tempest.common.rest_client import RestClientXML
+from tempest.services.compute.xml.common import Document
+from tempest.services.compute.xml.common import Element
+from tempest.services.compute.xml.common import xml_to_json
+from tempest.services.compute.xml.common import XMLNS_11
+
+
+class QuotasClientXML(RestClientXML):
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(QuotasClientXML, self).__init__(config, username, password,
+                                              auth_url, tenant_name)
+        self.service = self.config.compute.catalog_type
+
+    def _format_quota(self, q):
+        quota = {}
+        for k, v in q.items():
+            try:
+                v = int(v)
+            except ValueError:
+                pass
+
+            quota[k] = v
+
+        return quota
+
+    def _parse_array(self, node):
+        return [self._format_quota(xml_to_json(x)) for x in node]
+
+    def get_quota_set(self, tenant_id):
+        """List the quota set for a tenant."""
+
+        url = 'os-quota-sets/%s' % str(tenant_id)
+        resp, body = self.get(url, self.headers)
+        body = xml_to_json(etree.fromstring(body))
+        body = self._format_quota(body)
+        return resp, body
diff --git a/tempest/tests/compute/admin/test_quotas.py b/tempest/tests/compute/admin/test_quotas.py
index 6a7a5ea..b2b515a 100644
--- a/tempest/tests/compute/admin/test_quotas.py
+++ b/tempest/tests/compute/admin/test_quotas.py
@@ -18,23 +18,21 @@
 from nose.plugins.attrib import attr
 
 from tempest import exceptions
-from tempest.services.compute.admin.json import quotas_client as adm_quotas
-from tempest.tests.compute.base import BaseComputeTest
+from tempest.services.compute.admin.json \
+    import quotas_client as adm_quotas_json
+from tempest.services.compute.admin.xml import quotas_client as adm_quotas_xml
+from tempest.tests import compute
+from tempest.tests.compute import base
 
 
-class QuotasTest(BaseComputeTest):
+class QuotasAdminTestBase(object):
 
     @classmethod
     def setUpClass(cls):
-        super(QuotasTest, cls).setUpClass()
-        c_adm_user = cls.config.compute_admin.username
-        c_adm_pass = cls.config.compute_admin.password
-        c_adm_tenant = cls.config.compute_admin.tenant_name
-        auth_url = cls.config.identity.uri
-
-        cls.adm_client = adm_quotas.AdminQuotasClient(cls.config, c_adm_user,
-                                                      c_adm_pass, auth_url,
-                                                      c_adm_tenant)
+        cls.c_adm_user = cls.config.compute_admin.username
+        cls.c_adm_pass = cls.config.compute_admin.password
+        cls.c_adm_tenant = cls.config.compute_admin.tenant_name
+        cls.auth_url = cls.config.identity.uri
         cls.client = cls.os.quotas_client
         cls.identity_admin_client = cls._get_identity_admin_client()
         resp, tenants = cls.identity_admin_client.list_tenants()
@@ -63,7 +61,6 @@
                 cls.servers_client.delete_server(server['id'])
             except exceptions.NotFound:
                 continue
-        super(QuotasTest, cls).tearDownClass()
 
     @attr(type='smoke')
     def test_get_default_quotas(self):
@@ -155,3 +152,43 @@
         finally:
             self.adm_client.update_quota_set(self.demo_tenant_id,
                                              ram=default_mem_quota)
+
+
+class QuotasAdminTestJSON(QuotasAdminTestBase, base.BaseComputeAdminTestJSON,
+                          base.BaseComputeTest):
+
+    @classmethod
+    def setUpClass(cls):
+        base.BaseComputeAdminTestJSON.setUpClass()
+        base.BaseComputeTest.setUpClass()
+        super(QuotasAdminTestJSON, cls).setUpClass()
+
+        cls.adm_client = adm_quotas_json.AdminQuotasClientJSON(
+            cls.config, cls.c_adm_user, cls.c_adm_pass,
+            cls.auth_url, cls.c_adm_tenant)
+
+    @classmethod
+    def tearDownClass(cls):
+        super(QuotasAdminTestJSON, cls).tearDownClass()
+        base.BaseComputeTest.tearDownClass()
+
+
+class QuotasAdminTestXML(QuotasAdminTestBase, base.BaseComputeAdminTestXML,
+                         base.BaseComputeTest):
+
+    @classmethod
+    def setUpClass(cls):
+        base.BaseComputeAdminTestXML.setUpClass()
+        base.BaseComputeTest.setUpClass()
+        super(QuotasAdminTestXML, cls).setUpClass()
+
+        cls.adm_client = adm_quotas_xml.AdminQuotasClientXML(cls.config,
+                                                             cls.c_adm_user,
+                                                             cls.c_adm_pass,
+                                                             cls.auth_url,
+                                                             cls.c_adm_tenant)
+
+    @classmethod
+    def tearDownClass(cls):
+        super(QuotasAdminTestXML, cls).tearDownClass()
+        base.BaseComputeTest.tearDownClass()
diff --git a/tempest/tests/compute/test_quotas.py b/tempest/tests/compute/test_quotas.py
index 3dc2515..9306351 100644
--- a/tempest/tests/compute/test_quotas.py
+++ b/tempest/tests/compute/test_quotas.py
@@ -17,14 +17,13 @@
 
 from nose.plugins.attrib import attr
 
-from tempest.tests.compute.base import BaseComputeTest
+from tempest.tests.compute import base
 
 
-class QuotasTest(BaseComputeTest):
+class QuotasTestBase(object):
 
     @classmethod
     def setUpClass(cls):
-        super(QuotasTest, cls).setUpClass()
         cls.client = cls.quotas_client
         cls.admin_client = cls._get_identity_admin_client()
         resp, tenants = cls.admin_client.list_tenants()
@@ -47,3 +46,19 @@
             self.assertSequenceEqual(expected_quota_set, quota_set)
         except Exception:
             self.fail("Quota set for tenant did not have default limits")
+
+
+class QuotasTestJSON(QuotasTestBase, base.BaseComputeTestJSON):
+
+    @classmethod
+    def setUpClass(cls):
+        base.BaseComputeTestJSON.setUpClass()
+        super(QuotasTestJSON, cls).setUpClass()
+
+
+class QuotasTestXML(QuotasTestBase, base.BaseComputeTestXML):
+
+    @classmethod
+    def setUpClass(cls):
+        base.BaseComputeTestXML.setUpClass()
+        super(QuotasTestXML, cls).setUpClass()