Adding LB member operation test cases

Testcases for LB member operation were missing.
I have added LB member create, delete, update, list and show test cases.
Also xml support for the same is provided.

Change-Id: I0db9a6724856afebbc272f43fc3801cdaf3061e5
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index 3ae718c..378b4bf 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -58,9 +58,12 @@
         cls.ports = []
         cls.pools = []
         cls.vips = []
+        cls.members = []
 
     @classmethod
     def tearDownClass(cls):
+        for member in cls.members:
+            cls.client.delete_member(member['id'])
         for vip in cls.vips:
             cls.client.delete_vip(vip['id'])
         for pool in cls.pools:
@@ -135,3 +138,13 @@
         vip = body['vip']
         cls.vips.append(vip)
         return vip
+
+    @classmethod
+    def create_member(cls, protocol_port, pool):
+        """Wrapper utility that returns a test member."""
+        resp, body = cls.client.create_member("10.0.9.46",
+                                              protocol_port,
+                                              pool['id'])
+        member = body['member']
+        cls.members.append(member)
+        return member
diff --git a/tempest/api/network/test_load_balancer.py b/tempest/api/network/test_load_balancer.py
index d604c69..b0a6851 100644
--- a/tempest/api/network/test_load_balancer.py
+++ b/tempest/api/network/test_load_balancer.py
@@ -49,6 +49,7 @@
         cls.pool = cls.create_pool(pool_name, "ROUND_ROBIN",
                                    "HTTP", cls.subnet)
         cls.vip = cls.create_vip(vip_name, "HTTP", 80, cls.subnet, cls.pool)
+        cls.member = cls.create_member(80, cls.pool)
 
     @attr(type='smoke')
     def test_list_vips(self):
@@ -120,6 +121,41 @@
         pools = body['pools']
         self.assertIn(self.pool['id'], [p['id'] for p in pools])
 
+    @attr(type='smoke')
+    def test_list_members(self):
+        # Verify the member exists in the list of all members
+        resp, body = self.client.list_members()
+        self.assertEqual('200', resp['status'])
+        members = body['members']
+        self.assertIn(self.member['id'], [m['id'] for m in members])
+
+    @attr(type='smoke')
+    def test_create_update_delete_member(self):
+        # Creates a member
+        resp, body = self.client.create_member("10.0.9.46", 80,
+                                               self.pool['id'])
+        self.assertEqual('201', resp['status'])
+        member = body['member']
+        # Verification of member update
+        admin_state = [False, 'False']
+        resp, body = self.client.update_member(admin_state[0], member['id'])
+        self.assertEqual('200', resp['status'])
+        updated_member = body['member']
+        self.assertIn(updated_member['admin_state_up'], admin_state)
+        # Verification of member delete
+        resp, body = self.client.delete_member(member['id'])
+        self.assertEqual('204', resp['status'])
+
+    @attr(type='smoke')
+    def test_show_member(self):
+        # Verifies the details of a member
+        resp, body = self.client.show_member(self.member['id'])
+        self.assertEqual('200', resp['status'])
+        member = body['member']
+        self.assertEqual(self.member['id'], member['id'])
+        self.assertEqual(self.member['admin_state_up'],
+                         member['admin_state_up'])
+
 
 class LoadBalancerXML(LoadBalancerJSON):
     _interface = 'xml'
diff --git a/tempest/services/network/json/network_client.py b/tempest/services/network/json/network_client.py
index ceb4c62..fbcb6c1 100644
--- a/tempest/services/network/json/network_client.py
+++ b/tempest/services/network/json/network_client.py
@@ -490,3 +490,46 @@
         resp, body = self.get(uri, self.headers)
         body = json.loads(body)
         return resp, body
+
+    def list_members(self):
+        uri = '%s/lb/members' % (self.uri_prefix)
+        resp, body = self.get(uri, self.headers)
+        body = json.loads(body)
+        return resp, body
+
+    def create_member(self, address, protocol_port, pool_id):
+        post_body = {
+            "member": {
+                "protocol_port": protocol_port,
+                "pool_id": pool_id,
+                "address": address
+            }
+        }
+        body = json.dumps(post_body)
+        uri = '%s/lb/members' % (self.uri_prefix)
+        resp, body = self.post(uri, headers=self.headers, body=body)
+        body = json.loads(body)
+        return resp, body
+
+    def show_member(self, uuid):
+        uri = '%s/lb/members/%s' % (self.uri_prefix, uuid)
+        resp, body = self.get(uri, self.headers)
+        body = json.loads(body)
+        return resp, body
+
+    def delete_member(self, uuid):
+        uri = '%s/lb/members/%s' % (self.uri_prefix, uuid)
+        resp, body = self.delete(uri, self.headers)
+        return resp, body
+
+    def update_member(self, admin_state_up, member_id):
+        put_body = {
+            "member": {
+                "admin_state_up": admin_state_up
+            }
+        }
+        body = json.dumps(put_body)
+        uri = '%s/lb/members/%s' % (self.uri_prefix, member_id)
+        resp, body = self.put(uri, body=body, headers=self.headers)
+        body = json.loads(body)
+        return resp, body
diff --git a/tempest/services/network/xml/network_client.py b/tempest/services/network/xml/network_client.py
index 6881479..e8e362a 100755
--- a/tempest/services/network/xml/network_client.py
+++ b/tempest/services/network/xml/network_client.py
@@ -331,6 +331,45 @@
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
+    def list_members(self):
+        url = '%s/lb/members' % (self.uri_prefix)
+        resp, body = self.get(url, self.headers)
+        members = self._parse_array(etree.fromstring(body))
+        members = {"members": members}
+        return resp, members
+
+    def create_member(self, address, protocol_port, pool_id):
+        uri = '%s/lb/members' % (self.uri_prefix)
+        post_body = Element("member")
+        p1 = Element("address", address)
+        p2 = Element("protocol_port", protocol_port)
+        p3 = Element("pool_id", pool_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_member(self, member_id):
+        uri = '%s/lb/members/%s' % (self.uri_prefix, str(member_id))
+        return self.delete(uri, self.headers)
+
+    def show_member(self, member_id):
+        uri = '%s/lb/members/%s' % (self.uri_prefix, str(member_id))
+        resp, body = self.get(uri, self.headers)
+        body = _root_tag_fetcher_and_xml_to_json_parse(body)
+        return resp, body
+
+    def update_member(self, admin_state_up, member_id):
+        uri = '%s/lb/members/%s' % (self.uri_prefix, str(member_id))
+        put_body = Element("member")
+        p2 = Element("admin_state_up", admin_state_up)
+        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)