Merge "Add parallel test execution section to HACKING.rst"
diff --git a/tempest/api/network/test_load_balancer.py b/tempest/api/network/test_load_balancer.py
index 1c8c355..3880f4f 100644
--- a/tempest/api/network/test_load_balancer.py
+++ b/tempest/api/network/test_load_balancer.py
@@ -100,3 +100,7 @@
         vip = body['vip']
         self.assertEqual(self.vip['id'], vip['id'])
         self.assertEqual(self.vip['name'], vip['name'])
+
+
+class LoadBalancerXML(LoadBalancerJSON):
+    _interface = 'xml'
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index 7e116b9..a2b4ab3 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -58,49 +58,11 @@
     def setUpClass(cls):
         super(NetworksTestJSON, cls).setUpClass()
         cls.network = cls.create_network()
-        cls.network1 = cls.create_network()
-        cls.network2 = cls.create_network()
         cls.name = cls.network['name']
         cls.subnet = cls.create_subnet(cls.network)
         cls.cidr = cls.subnet['cidr']
         cls.port = cls.create_port(cls.network)
 
-    def _delete_networks(self, created_networks):
-        for n in created_networks:
-            resp, body = self.client.delete_network(n['id'])
-            self.assertEqual(204, resp.status)
-        # Asserting that the networks are not found in the list after deletion
-        resp, body = self.client.list_networks()
-        networks_list = list()
-        for network in body['networks']:
-            networks_list.append(network['id'])
-        for n in created_networks:
-            self.assertNotIn(n['id'], networks_list)
-
-    def _delete_subnets(self, created_subnets):
-        for n in created_subnets:
-            resp, body = self.client.delete_subnet(n['id'])
-            self.assertEqual(204, resp.status)
-        # Asserting that the subnets are not found in the list after deletion
-        resp, body = self.client.list_subnets()
-        subnets_list = list()
-        for subnet in body['subnets']:
-            subnets_list.append(subnet['id'])
-        for n in created_subnets:
-            self.assertNotIn(n['id'], subnets_list)
-
-    def _delete_ports(self, created_ports):
-        for n in created_ports:
-            resp, body = self.client.delete_port(n['id'])
-            self.assertEqual(204, resp.status)
-        # Asserting that the ports are not found in the list after deletion
-        resp, body = self.client.list_ports()
-        ports_list = list()
-        for port in body['ports']:
-            ports_list.append(port['id'])
-        for n in created_ports:
-            self.assertNotIn(n['id'], ports_list)
-
     @attr(type='smoke')
     def test_create_update_delete_network_subnet(self):
         # Creates a network
@@ -240,6 +202,75 @@
         self.assertRaises(exceptions.NotFound, self.client.show_port,
                           non_exist_id)
 
+
+class NetworksTestXML(NetworksTestJSON):
+    _interface = 'xml'
+
+
+class BulkNetworkOpsJSON(base.BaseNetworkTest):
+    _interface = 'json'
+
+    """
+    Tests the following operations in the Neutron API using the REST client for
+    Neutron:
+
+        bulk network creation
+        bulk subnet creation
+        bulk subnet creation
+        list tenant's networks
+
+    v2.0 of the Neutron API is assumed. It is also assumed that the following
+    options are defined in the [network] section of etc/tempest.conf:
+
+        tenant_network_cidr with a block of cidr's from which smaller blocks
+        can be allocated for tenant networks
+
+        tenant_network_mask_bits with the mask bits to be used to partition the
+        block defined by tenant-network_cidr
+    """
+
+    @classmethod
+    def setUpClass(cls):
+        super(BulkNetworkOpsJSON, cls).setUpClass()
+        cls.network1 = cls.create_network()
+        cls.network2 = cls.create_network()
+
+    def _delete_networks(self, created_networks):
+        for n in created_networks:
+            resp, body = self.client.delete_network(n['id'])
+            self.assertEqual(204, resp.status)
+        # Asserting that the networks are not found in the list after deletion
+        resp, body = self.client.list_networks()
+        networks_list = list()
+        for network in body['networks']:
+            networks_list.append(network['id'])
+        for n in created_networks:
+            self.assertNotIn(n['id'], networks_list)
+
+    def _delete_subnets(self, created_subnets):
+        for n in created_subnets:
+            resp, body = self.client.delete_subnet(n['id'])
+            self.assertEqual(204, resp.status)
+        # Asserting that the subnets are not found in the list after deletion
+        resp, body = self.client.list_subnets()
+        subnets_list = list()
+        for subnet in body['subnets']:
+            subnets_list.append(subnet['id'])
+        for n in created_subnets:
+            self.assertNotIn(n['id'], subnets_list)
+
+    def _delete_ports(self, created_ports):
+        for n in created_ports:
+            resp, body = self.client.delete_port(n['id'])
+            self.assertEqual(204, resp.status)
+        # Asserting that the ports are not found in the list after deletion
+        resp, body = self.client.list_ports()
+        ports_list = list()
+        for port in body['ports']:
+            ports_list.append(port['id'])
+        for n in created_ports:
+            self.assertNotIn(n['id'], ports_list)
+
     @attr(type='smoke')
     def test_bulk_create_delete_network(self):
         # Creates 2 networks in one request
@@ -326,5 +357,5 @@
             self.assertIn(n['id'], ports_list)
 
 
-class NetworksTestXML(NetworksTestJSON):
+class BulkNetworkOpsXML(BulkNetworkOpsJSON):
     _interface = 'xml'
diff --git a/tempest/services/network/xml/network_client.py b/tempest/services/network/xml/network_client.py
index 8303bc0..6881479 100755
--- a/tempest/services/network/xml/network_client.py
+++ b/tempest/services/network/xml/network_client.py
@@ -249,6 +249,88 @@
         ports = {"ports": ports}
         return resp, ports
 
+    def list_vips(self):
+        url = '%s/lb/vips' % (self.uri_prefix)
+        resp, body = self.get(url, self.headers)
+        vips = self._parse_array(etree.fromstring(body))
+        vips = {"vips": vips}
+        return resp, vips
+
+    def create_vip(self, name, protocol, protocol_port, subnet_id, pool_id):
+        uri = '%s/lb/vips' % (self.uri_prefix)
+        post_body = Element("vip")
+        p1 = Element("name", name)
+        p2 = Element("protocol", protocol)
+        p3 = Element("protocol_port", protocol_port)
+        p4 = Element("subnet_id", subnet_id)
+        p5 = Element("pool_id", pool_id)
+        post_body.append(p1)
+        post_body.append(p2)
+        post_body.append(p3)
+        post_body.append(p4)
+        post_body.append(p5)
+        resp, body = self.post(uri, str(Document(post_body)), self.headers)
+        body = _root_tag_fetcher_and_xml_to_json_parse(body)
+        return resp, body
+
+    def delete_vip(self, vip_id):
+        uri = '%s/lb/vips/%s' % (self.uri_prefix, str(vip_id))
+        return self.delete(uri, self.headers)
+
+    def show_vip(self, vip_id):
+        uri = '%s/lb/vips/%s' % (self.uri_prefix, str(vip_id))
+        resp, body = self.get(uri, self.headers)
+        body = _root_tag_fetcher_and_xml_to_json_parse(body)
+        return resp, body
+
+    def update_vip(self, vip_id, new_name):
+        uri = '%s/lb/vips/%s' % (self.uri_prefix, str(vip_id))
+        put_body = Element("vip")
+        p2 = Element("name", new_name)
+        put_body.append(p2)
+        resp, body = self.put(uri, str(Document(put_body)), self.headers)
+        body = _root_tag_fetcher_and_xml_to_json_parse(body)
+        return resp, body
+
+    def list_pools(self):
+        url = '%s/lb/pools' % (self.uri_prefix)
+        resp, body = self.get(url, self.headers)
+        pools = self._parse_array(etree.fromstring(body))
+        pools = {"pools": pools}
+        return resp, pools
+
+    def create_pool(self, name, lb_method, protocol, subnet_id):
+        uri = '%s/lb/pools' % (self.uri_prefix)
+        post_body = Element("pool")
+        p1 = Element("lb_method", lb_method)
+        p2 = Element("protocol", protocol)
+        p3 = Element("subnet_id", subnet_id)
+        post_body.append(p1)
+        post_body.append(p2)
+        post_body.append(p3)
+        resp, body = self.post(uri, str(Document(post_body)), self.headers)
+        body = _root_tag_fetcher_and_xml_to_json_parse(body)
+        return resp, body
+
+    def delete_pool(self, pool_id):
+        uri = '%s/lb/pools/%s' % (self.uri_prefix, str(pool_id))
+        return self.delete(uri, self.headers)
+
+    def show_pool(self, pool_id):
+        uri = '%s/lb/pools/%s' % (self.uri_prefix, str(pool_id))
+        resp, body = self.get(uri, self.headers)
+        body = _root_tag_fetcher_and_xml_to_json_parse(body)
+        return resp, body
+
+    def update_pool(self, pool_id, new_name):
+        uri = '%s/lb/pools/%s' % (self.uri_prefix, str(pool_id))
+        put_body = Element("pool")
+        p2 = Element("name", new_name)
+        put_body.append(p2)
+        resp, body = self.put(uri, str(Document(put_body)), self.headers)
+        body = _root_tag_fetcher_and_xml_to_json_parse(body)
+        return resp, body
+
 
 def _root_tag_fetcher_and_xml_to_json_parse(xml_returned_body):
     body = ET.fromstring(xml_returned_body)