Added Secret Metadata client and unit tests

This change adds a REST client and corresponding
unit tests for Barbican's Metadata API resource.

Change-Id: Icd2c6ae1f476b57e4108faada0bda5f1aebc640b
diff --git a/barbican_tempest_plugin/plugin.py b/barbican_tempest_plugin/plugin.py
index 7eee973..68a971a 100644
--- a/barbican_tempest_plugin/plugin.py
+++ b/barbican_tempest_plugin/plugin.py
@@ -44,6 +44,7 @@
             'client_names': [
                 'ConsumerClient',
                 'ContainerClient',
+                'SecretMetadataClient',
                 'SecretClient'
             ],
         }
diff --git a/barbican_tempest_plugin/services/key_manager/json/__init__.py b/barbican_tempest_plugin/services/key_manager/json/__init__.py
index 0e56400..ffb1734 100644
--- a/barbican_tempest_plugin/services/key_manager/json/__init__.py
+++ b/barbican_tempest_plugin/services/key_manager/json/__init__.py
@@ -18,5 +18,12 @@
     import ContainerClient
 from barbican_tempest_plugin.services.key_manager.json.secret_client \
     import SecretClient
+from barbican_tempest_plugin.services.key_manager.json.secret_metadata_client \
+    import SecretMetadataClient
 
-__all__ = ['ConsumerClient', 'ContainerClient', 'SecretClient']
+__all__ = [
+    'ConsumerClient',
+    'ContainerClient',
+    'SecretMetadataClient',
+    'SecretClient'
+]
diff --git a/barbican_tempest_plugin/services/key_manager/json/secret_metadata_client.py b/barbican_tempest_plugin/services/key_manager/json/secret_metadata_client.py
new file mode 100644
index 0000000..dae8ae3
--- /dev/null
+++ b/barbican_tempest_plugin/services/key_manager/json/secret_metadata_client.py
@@ -0,0 +1,71 @@
+# Copyright (c) 2017 Johns Hopkins University Applied Physics Laboratory
+#
+# 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 json
+
+from tempest import config
+from tempest.lib.common import rest_client
+
+CONF = config.CONF
+
+
+class SecretMetadataClient(rest_client.RestClient):
+
+    def get_secret_metadata(self, secret_id):
+        resp, body = self.get("v1/secrets/%s/metadata" % secret_id)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def put_secret_metadata(self, secret_id, **kwargs):
+        body_dict = {'metadata': kwargs}
+        uri = "v1/secrets/%s/metadata" % secret_id
+        resp, body = self.put(uri, json.dumps(body_dict))
+        self.expected_success(201, resp.status)
+        return self._parse_resp(body)
+
+    def get_secret_metadata_by_key(self, secret_id, key):
+        uri = "v1/secrets/{uuid}/metadata/{key}".format(uuid=secret_id,
+                                                        key=key)
+        resp, body = self.get(uri)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def create_key_value_pair(self, secret_id, key, value):
+        body_dict = {
+            'key': key,
+            'value': value
+        }
+        resp, body = self.post("v1/secrets/%s/metadata" % secret_id,
+                               json.dumps(body_dict))
+        self.expected_success(201, resp.status)
+        return self._parse_resp(body)
+
+    def update_secret_metadata(self, secret_id, key, value):
+        uri = "v1/secrets/{uuid}/metadata/{key}".format(uuid=secret_id,
+                                                        key=key)
+        body_dict = {
+            'key': key,
+            'value': value
+        }
+        resp, body = self.put(uri, json.dumps(body_dict))
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def delete_secret_metadata_by_key(self, secret_id, key):
+        uri = "v1/secrets/{uuid}/metadata/{key}".format(uuid=secret_id,
+                                                        key=key)
+        resp, body = self.delete(uri)
+        self.expected_success(204, resp.status)
+        return self._parse_resp(body)
diff --git a/barbican_tempest_plugin/tests/api/base.py b/barbican_tempest_plugin/tests/api/base.py
index c5a7597..58f6bbf 100644
--- a/barbican_tempest_plugin/tests/api/base.py
+++ b/barbican_tempest_plugin/tests/api/base.py
@@ -65,6 +65,9 @@
         cls.container_client = os.secret_v1.ContainerClient(
             service='key-manager'
         )
+        cls.secret_metadata_client = os.secret_v1.SecretMetadataClient(
+            service='key-manager'
+        )
         cls.secret_client = os.secret_v1.SecretClient(service='key-manager')
 
     @classmethod
diff --git a/barbican_tempest_plugin/tests/api/test_secret_metadata.py b/barbican_tempest_plugin/tests/api/test_secret_metadata.py
new file mode 100644
index 0000000..5c4cd36
--- /dev/null
+++ b/barbican_tempest_plugin/tests/api/test_secret_metadata.py
@@ -0,0 +1,65 @@
+# Copyright 2017 Johns Hopkins Applied Physics Lab
+# 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 barbican_tempest_plugin.tests.api import base
+
+
+class SecretMetadataTest(base.BaseKeyManagerTest):
+    """Metadata API test"""
+    def test_secret_metadata(self):
+        # Create a secret
+        sec = self.create_secret()
+        uuid = base._get_uuid(sec['secret_ref'])
+
+        # Add multiple metadata fields
+        self.secret_metadata_client.put_secret_metadata(
+            uuid,
+            description='contains the AES key',
+            geolocation='12.3456, -98.7654'
+        )
+
+        metadata = self.secret_metadata_client.get_secret_metadata(uuid)
+        self.assertEqual(2, len(metadata.keys()))
+        self.assertIn('description', metadata.keys())
+        self.assertIn('geolocation', metadata.keys())
+        self.assertEqual('contains the AES key', metadata['description'])
+        self.assertEqual('12.3456, -98.7654', metadata['geolocation'])
+
+        # Add a single metadata field
+        self.secret_metadata_client.create_key_value_pair(
+            uuid,
+            key='extra',
+            value='extra value'
+        )
+        metadata = self.secret_metadata_client.get_secret_metadata(uuid)
+        self.assertEqual(3, len(metadata.keys()))
+        self.assertEqual('extra value', metadata['extra'])
+
+        # Modify the metadata field
+        self.secret_metadata_client.update_secret_metadata(
+            uuid,
+            key='extra',
+            value='new value'
+        )
+        metadata = self.secret_metadata_client.get_secret_metadata(uuid)
+        self.assertEqual('new value', metadata['extra'])
+
+        # Delete the extra key-value pair
+        self.secret_metadata_client.delete_secret_metadata_by_key(
+            uuid,
+            'extra'
+        )
+        metadata = self.secret_metadata_client.get_secret_metadata(uuid)
+        self.assertEqual(2, len(metadata.keys()))