From b7f5d564a4eb330c5c6941be57325a81acf0ef39 Mon Sep 17 00:00:00 2001 From: Thomas Dinkjian Date: Fri, 30 Jan 2015 15:09:26 -0600 Subject: [PATCH] Adds base behaviors, secret behaviors and the secret smoke tests Base behaviors was copied from barbican API and was not changed. Secret behaviors contains all the actions the client can take on secrets Secret smoke tests are all positive tests, and they test the basic functions of secrets. Change-Id: I84029fb85626206f0a52c5aab9a6246b6dffa809 --- functionaltests/client/__init__.py | 1 + .../client/v1/behaviors/base_behaviors.py | 52 +++++++ .../client/v1/behaviors/secret_behaviors.py | 95 ++++++++++++ .../client/v1/smoke/test_secrets.py | 145 ++++++++++++++++++ 4 files changed, 293 insertions(+) create mode 100644 functionaltests/client/v1/behaviors/base_behaviors.py create mode 100644 functionaltests/client/v1/behaviors/secret_behaviors.py create mode 100644 functionaltests/client/v1/smoke/test_secrets.py diff --git a/functionaltests/client/__init__.py b/functionaltests/client/__init__.py index 70a50994..7453542c 100644 --- a/functionaltests/client/__init__.py +++ b/functionaltests/client/__init__.py @@ -32,3 +32,4 @@ CONF.register_opt(cfg.StrOpt('password'), group='keymanager') CONF.register_opt(cfg.StrOpt('project_name'), group='keymanager') CONF.register_opt(cfg.StrOpt('project_id'), group='keymanager') CONF.register_opt(cfg.IntOpt('max_payload_size'), group='keymanager') +CONF.register_opt(cfg.StrOpt('project_domain_name'), group='keymanager') diff --git a/functionaltests/client/v1/behaviors/base_behaviors.py b/functionaltests/client/v1/behaviors/base_behaviors.py new file mode 100644 index 00000000..7237d922 --- /dev/null +++ b/functionaltests/client/v1/behaviors/base_behaviors.py @@ -0,0 +1,52 @@ +""" +Copyright 2015 Rackspace + +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 os + +from tempest.openstack.common import log as logging + + +class BaseBehaviors(object): + + def __init__(self, client): + self.LOG = logging.getLogger(type(self).__name__) + self.client = client + self.created_entities = [] + + def get_json(self, response): + json_data = dict() + + try: + json_data = response.json() + except ValueError as e: + self.LOG.exception(e) + self.LOG.error("Error converting response to JSON: %s", e.message) + self.LOG.error("Response Content: %s", response.content) + + return json_data + + def get_id_from_href(self, href): + """Returns the id from reference. + + The id must be the last item in the href. + + :param href: The href containing the id. + :returns the id portion of the href + """ + + item_id = None + if href and len(href) > 0: + base, item_id = os.path.split(href) + return item_id diff --git a/functionaltests/client/v1/behaviors/secret_behaviors.py b/functionaltests/client/v1/behaviors/secret_behaviors.py new file mode 100644 index 00000000..89d19f05 --- /dev/null +++ b/functionaltests/client/v1/behaviors/secret_behaviors.py @@ -0,0 +1,95 @@ +""" +Copyright 2015 Rackspace + +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 functionaltests.client.v1.behaviors import base_behaviors + + +class SecretBehaviors(base_behaviors.BaseBehaviors): + + def create_secret(self, data): + """Creates a Barbican client secret object. + + This does not store the object in the database. + + :param data: Data for creation of the barbican object. + :return: Barbican client secret object + """ + return self.client.secrets.create(**data) + + def store_secret(self, secret): + """Stores a secret object in the barbican datastore. + + Creating a secret in the client only creates the Secret object. + The secret is not saved to the database until a store is called. + + :param secret: A barbican client secret object + :return: The ref to the created secret + """ + + resp = secret.store() + + if resp: + self.created_entities.append(resp) + + return resp + + def get_secret(self, secret_ref, payload_content_type=None): + """Retrieves a secret and its payload. + + :param secret_ref: A secret reference + :param payload_content_type: The secrets content type + :return: A barbican secret object with all meta and payload + information + """ + + return self.client.secrets.get( + secret_ref, + payload_content_type=payload_content_type) + + def get_secrets(self, limit=10, offset=0): + """Handles getting a list of secrets. + + :param limit: limits number of returned secrets + :param offset: represents how many records to skip before retrieving + the list + :return: A list of secret objects + """ + + return self.client.secrets.list(limit=limit, offset=offset) + + def delete_secret(self, secret_ref, expected_fail=False): + """Delete a secret. + + :param secret_ref: HATEOS ref of the secret to be deleted + :param expected_fail: If test is expected to fail the deletion + :return: On failure will return a string + """ + resp = self.client.secrets.delete(secret_ref) + + if not expected_fail: + self.created_entities.remove(secret_ref) + + return resp + + def delete_all_created_secrets(self): + """Delete all of the secrets that we have created.""" + slist = [] + + for entity in self.created_entities: + slist.append(entity) + + for secret_ref in slist: + self.delete_secret(secret_ref) diff --git a/functionaltests/client/v1/smoke/test_secrets.py b/functionaltests/client/v1/smoke/test_secrets.py new file mode 100644 index 00000000..8b7be335 --- /dev/null +++ b/functionaltests/client/v1/smoke/test_secrets.py @@ -0,0 +1,145 @@ +# Copyright (c) 2015 Rackspace, Inc. +# +# 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 testtools import testcase +from functionaltests.client import base +from functionaltests.client.v1.behaviors import secret_behaviors +from functionaltests import utils + +secret_create_defaults_data = { + "name": "AES key", + "expiration": "2018-02-28T19:14:44.180394", + "algorithm": "aes", + "bit_length": 256, + "mode": "cbc", + "payload": "gF6+lLoF3ohA9aPRpt+6bQ==", + "payload_content_type": "application/octet-stream", + "payload_content_encoding": "base64", +} + +secret_create_nones_data = { + "name": None, + "expiration": None, + "algorithm": None, + "bit_length": None, + "mode": None, + "payload": "gF6+lLoF3ohA9aPRpt+6bQ==", + "payload_content_type": "application/octet-stream", + "payload_content_encoding": "base64", +} + + +@utils.parameterized_test_case +class SecretsTestCase(base.TestCase): + + def setUp(self): + super(SecretsTestCase, self).setUp() + self.behaviors = secret_behaviors.SecretBehaviors(self.barbicanclient) + + def tearDown(self): + self.behaviors.delete_all_created_secrets() + super(SecretsTestCase, self).tearDown() + + @testcase.attr('positive') + def test_create_secret_defaults(self): + """Creates a secret with default values""" + test_model = self.behaviors.create_secret(secret_create_defaults_data) + + secret_ref = self.behaviors.store_secret(test_model) + self.assertIsNotNone(secret_ref) + + @testcase.attr('positive') + def test_secret_create_defaults_no_expiration(self): + """Covers creating a secret without an expiration.""" + test_model = self.behaviors.create_secret(secret_create_defaults_data) + test_model.expiration = None + + secret_ref = self.behaviors.store_secret(test_model) + self.assertIsNotNone(secret_ref) + + @utils.parameterized_dataset({ + 'alphanumeric': ['1f34ds'], + 'punctuation': ['~!@#$%^&*()_+`-={}[]|:;<>,.?'], + 'uuid': ['54262d9d-4bc7-4821-8df0-dc2ca8e112bb'], + 'len_255': [str(bytearray().zfill(255))], + 'empty': [''], + 'null': [None] + }) + @testcase.attr('positive') + def test_secret_get_defaults_metadata_w_valid_name(self, name): + """Covers getting and checking a secret's metadata.""" + test_model = self.behaviors.create_secret(secret_create_defaults_data) + test_model.name = name + + secret_ref = self.behaviors.store_secret(test_model) + self.assertIsNotNone(secret_ref) + + get_resp = self.behaviors.get_secret(secret_ref) + self.assertEqual(get_resp.status, "ACTIVE") + self.assertEqual(get_resp.name, name) + self.assertEqual(get_resp.mode, test_model.mode) + self.assertEqual(get_resp.algorithm, test_model.algorithm) + self.assertEqual(get_resp.bit_length, test_model.bit_length) + + @testcase.attr('positive') + def test_secret_delete_defaults(self): + """Covers deleting a secret.""" + test_model = self.behaviors.create_secret(secret_create_defaults_data) + + secret_ref = self.behaviors.store_secret(test_model) + + del_response = self.behaviors.delete_secret(secret_ref) + self.assertIsNone(del_response) + + @testcase.attr('positive') + def test_secret_delete_minimal_secret_w_no_metadata(self): + """Covers deleting a secret with nones data.""" + test_model = self.behaviors.create_secret(secret_create_nones_data) + + secret_ref = self.behaviors.store_secret(test_model) + self.assertIsNotNone(secret_ref) + + del_resp = self.behaviors.delete_secret(secret_ref) + self.assertIsNone(del_resp) + + @testcase.attr('positive') + def test_secret_get_defaults_payload(self): + """Covers getting a secret's payload data.""" + test_model = self.behaviors.create_secret(secret_create_defaults_data) + + secret_ref = self.behaviors.store_secret(test_model) + + get_resp = self.behaviors.get_secret( + secret_ref, + payload_content_type=test_model.payload_content_type) + self.assertEqual(get_resp.payload, test_model.payload) + + @testcase.attr('positive') + def test_secrets_get_defaults_multiple_secrets(self): + """Covers getting a list of secrets. + + Creates 11 secrets then returns a list of 5 secrets + """ + limit = 5 + offset = 5 + total = 10 + + for i in range(0, total + 1): + test_model = self.behaviors.create_secret( + secret_create_defaults_data) + self.behaviors.store_secret(test_model) + + secret_list = self.behaviors.get_secrets(limit=limit, + offset=offset) + self.assertEqual(len(secret_list), limit)