diff options
author | Steve Heyman <steve.heyman@rackspace.com> | 2015-05-02 15:22:28 -0500 |
---|---|---|
committer | Steve Heyman <steve.heyman@rackspace.com> | 2015-05-12 12:52:37 -0500 |
commit | 82daee29fb9ccc191e01b7d8d06b77ffd15e6059 (patch) | |
tree | 9b9fcc4dbdba8aa52ce6f44809b76ca9973053f9 | |
parent | 70da0d01f1da50c76231565548f730d3141c76e5 (diff) | |
download | python-barbicanclient-82daee29fb9ccc191e01b7d8d06b77ffd15e6059.tar.gz |
Create behaviors for secrets
To prevent violations of DRY this CR will create behaviors for
secrets that will be available to other barbican resource testcases.
Change-Id: I075b89156e8af6c0a2b0e196a5f3e70c6b41160d
-rw-r--r-- | functionaltests/cli/base.py | 126 | ||||
-rw-r--r-- | functionaltests/cli/v1/behaviors/__init__.py | 0 | ||||
-rw-r--r-- | functionaltests/cli/v1/behaviors/base_behaviors.py | 134 | ||||
-rw-r--r-- | functionaltests/cli/v1/behaviors/secret_behaviors.py | 121 | ||||
-rw-r--r-- | functionaltests/cli/v1/smoke/test_help.py | 4 | ||||
-rw-r--r-- | functionaltests/cli/v1/smoke/test_secret.py | 142 |
6 files changed, 278 insertions, 249 deletions
diff --git a/functionaltests/cli/base.py b/functionaltests/cli/base.py index 6f7384b..23fcff5 100644 --- a/functionaltests/cli/base.py +++ b/functionaltests/cli/base.py @@ -14,136 +14,10 @@ See the License for the specific language governing permissions and limitations under the License. """ -import exceptions as exc -import re -import six - - from functionaltests.base import BaseTestCase -from barbicanclient import barbican -from tempest import config - -CONF = config.CONF - class CmdLineTestCase(BaseTestCase): def setUp(self): self.LOG.info('Starting: %s', self._testMethodName) super(CmdLineTestCase, self).setUp() - - self.cmdline_client = barbican.Barbican() - - def add_auth_and_endpoint(self, arg_list): - """ Update an argument list with authentication and endpoint data - - Keystone v3 introduced the concept of a domain, so only the v3 - flavor will include domain names. - - Keystone v3 changed "tenant" to "project" so the v3 flavor uses - the term 'project' in its args while v2 uses 'tenant'. - - Both v2 and v2 require the auth URL, userid/password, and barbican - endpoint URL. - - :param arg_list: the current argument list - :return: the argument list is updated with the authentication and - endpoint args - """ - if 'v3' in CONF.identity.auth_version.lower(): - arg_list.extend(['--os-auth-url', CONF.identity.uri_v3]) - arg_list.extend(['--os-project-name', CONF.keymanager.project_name]) - # NOTE(jaosorior): Should we add the user_domain_name to the - # config? - arg_list.extend( - ['--os-user-domain-name', CONF.keymanager.project_domain_name]) - arg_list.extend( - ['--os-project-domain-name', - CONF.keymanager.project_domain_name]) - arg_list.extend(['--os-identity-api-version', '3.0']) - else: - arg_list.extend(['--os-auth-url', CONF.identity.uri]) - arg_list.extend(['--os-tenant-name', CONF.keymanager.project_name]) - arg_list.extend(['--os-identity-api-version', '2.0']) - - arg_list.extend(['--os-username', CONF.keymanager.username, - '--os-password', CONF.keymanager.password]) - - arg_list.extend(['--endpoint', CONF.keymanager.url]) - self.LOG.info('updated command string: %s', arg_list) - - def issue_barbican_command(self, argv): - """ Issue the barbican command and return its output. - - The barbican command sometimes raises SystemExit, but not always, so - we will handle either situation here. - - Also we will create new stdout/stderr streams for each command so that - any output from a previous command doesn't contaminate the new command. - - :param argv: dict of keyword arguments to pass to the command. This - does NOT include "barbican" - that's not needed. - :return: Two strings - one the captured stdout and one the captured - stderr. - """ - - try: - self.cmdline_client.stdout = six.StringIO() - self.cmdline_client.stderr = six.StringIO() - self.cmdline_client.run(argv) - except exc.SystemExit: - pass - - outstr = self.cmdline_client.stdout.getvalue() - errstr = self.cmdline_client.stderr.getvalue() - - return outstr, errstr - - def _prettytable_to_secret(self, str): - """ Create a dict from the values in a PrettyTable string. - - :param str: a string representing a PrettyTable output from a - barbican secret store or get command. - :return: a dict containing the fields and values from the output. - """ - retval = {} - if str is not None and len(str) > 0: - table_body = re.split('\+-*\+-*\+\n', str)[2:-1] - lines = table_body[0].split('\n') - for line in lines: - if len(line) > 0: - row = line.split('|') - key = row[1].strip() - value = row[2].strip() - retval[key] = value - return retval - - def _prettytable_to_secret_list(self, str): - """ Create a list from the values in a PrettyTable string. - - :param str: a string representing a PrettyTable output from a - barbican secret list command. - :return: a list containing one dict for each column in the table. - If there are no entries then an empty list will be returned. - """ - retval = [] - if str is not None and len(str) > 0: - rows = re.findall('\|(.*)?\n', str) - # Remove header - rows.pop(0) - for row in rows: - # Parse out the entire row - (href, name, created, status, content_types, algorithm, - bit_length, mode, expiration) = re.findall('\s*(.*?)\s*\|', - row) - entry_dict = {'Secret href': href, - 'Name': name, - 'Created': created, - 'Status': status, - 'Content types': content_types, - 'Algorithm': algorithm, - 'Bit length': bit_length, - 'Mode': mode, - 'Expiration': expiration} - retval.append(entry_dict) - return retval diff --git a/functionaltests/cli/v1/behaviors/__init__.py b/functionaltests/cli/v1/behaviors/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/functionaltests/cli/v1/behaviors/__init__.py diff --git a/functionaltests/cli/v1/behaviors/base_behaviors.py b/functionaltests/cli/v1/behaviors/base_behaviors.py new file mode 100644 index 0000000..bc19d03 --- /dev/null +++ b/functionaltests/cli/v1/behaviors/base_behaviors.py @@ -0,0 +1,134 @@ +""" +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 exceptions as exc +import logging +import re +import six + +from barbicanclient import barbican +from tempest import config + +CONF = config.CONF + + +class BaseBehaviors(object): + + def __init__(self): + self.LOG = logging.getLogger(type(self).__name__) + self.cmdline_client = barbican.Barbican() + + def add_auth_and_endpoint(self, arg_list): + """ Update an argument list with authentication and endpoint data + + Keystone v3 introduced the concept of a domain, so only the v3 + flavor will include domain names. + + Keystone v3 changed "tenant" to "project" so the v3 flavor uses + the term 'project' in its args while v2 uses 'tenant'. + + Both v2 and v2 require the auth URL, userid/password, and barbican + endpoint URL. + + :param arg_list: the current argument list + :return: the argument list is updated with the authentication and + endpoint args + """ + if 'v3' in CONF.identity.auth_version.lower(): + arg_list.extend(['--os-auth-url', CONF.identity.uri_v3]) + arg_list.extend( + ['--os-project-name', CONF.keymanager.project_name]) + # NOTE(jaosorior): Should we add the user_domain_name to the + # config? + arg_list.extend( + ['--os-user-domain-name', CONF.keymanager.project_domain_name]) + arg_list.extend( + ['--os-project-domain-name', + CONF.keymanager.project_domain_name]) + else: + arg_list.extend(['--os-auth-url', CONF.identity.auth_uri]) + arg_list.extend(['--os-tenant-name', CONF.keymanager.project_name]) + + arg_list.extend(['--os-username', CONF.keymanager.username, + '--os-password', CONF.keymanager.password]) + + arg_list.extend(['--endpoint', CONF.keymanager.url]) + self.LOG.info('updated command string: %s', arg_list) + + def issue_barbican_command(self, argv): + """ Issue the barbican command and return its output. + + The barbican command sometimes raises SystemExit, but not always, so + we will handle either situation here. + + Also we will create new stdout/stderr streams for each command so that + any output from a previous command doesn't contaminate the new command. + + :param argv: dict of keyword arguments to pass to the command. This + does NOT include "barbican" - that's not needed. + :return: Two strings - one the captured stdout and one the captured + stderr. + """ + + try: + self.cmdline_client.stdout = six.StringIO() + self.cmdline_client.stderr = six.StringIO() + self.cmdline_client.run(argv) + except exc.SystemExit: + pass + + outstr = self.cmdline_client.stdout.getvalue() + errstr = self.cmdline_client.stderr.getvalue() + + return outstr, errstr + + def _prettytable_to_dict(self, str): + """ Create a dict from the values in a PrettyTable string. + + :param str: a string representing a PrettyTable output from a + barbican secret store or get command. + :return: a dict containing the fields and values from the output. + """ + retval = {} + if str is not None and len(str) > 0: + table_body = re.split('\+-*\+-*\+\n', str)[2:-1] + lines = table_body[0].split('\n') + for line in lines: + if len(line) > 0: + row = line.split('|') + key = row[1].strip() + value = row[2].strip() + retval[key] = value + return retval + + def _prettytable_to_list(self, str): + """ Create a list from the values in a PrettyTable string. + + :param str: a string representing a PrettyTable output from a + barbican secret list command. + :return: a list containing one dict for each column in the table. + If there are no entries then an empty list will be returned. + """ + retval = [] + if str is not None and len(str) > 0: + rows = re.findall('\|(.*)?\n', str) + # Remove header + header_row = rows.pop(0) + key_names = re.findall('\s*(.*?)\s*\|', header_row) + for row in rows: + values = re.findall('\s*(.*?)\s*\|', row) + entry_dict = dict(zip(key_names, values)) + retval.append(entry_dict) + return retval diff --git a/functionaltests/cli/v1/behaviors/secret_behaviors.py b/functionaltests/cli/v1/behaviors/secret_behaviors.py new file mode 100644 index 0000000..8086780 --- /dev/null +++ b/functionaltests/cli/v1/behaviors/secret_behaviors.py @@ -0,0 +1,121 @@ +# 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. + +import logging + +import base_behaviors + +class SecretBehaviors(base_behaviors.BaseBehaviors): + + def __init__(self): + super(SecretBehaviors, self).__init__() + self.LOG = logging.getLogger(type(self).__name__) + self.secret_hrefs_to_delete = [] + + def delete_secret(self, secret_href): + """ Delete a secret + + :param secret_href the href to the secret to delete + """ + argv = ['secret', 'delete'] + self.add_auth_and_endpoint(argv) + argv.extend([secret_href]) + + stdout, stderr = self.issue_barbican_command(argv) + + self.secret_hrefs_to_delete.remove(secret_href) + + def store_secret(self, payload="Payload for testing"): + """ Store (aka create) a secret + :param payload The payload to use when storing the secret. + + :return: the href to the newly created secret + """ + argv = ['secret', 'store'] + self.add_auth_and_endpoint(argv) + argv.extend(['--payload', payload]) + + stdout, stderr = self.issue_barbican_command(argv) + + secret_data = self._prettytable_to_dict(stdout) + + secret_href = secret_data['Secret href'] + self.secret_hrefs_to_delete.append(secret_href) + return secret_href + + def get_secret(self, secret_href): + """ Get a secret + + :param: the href to a secret + :return dict of secret values, or an empty dict if the secret + is not found. + """ + argv = ['secret', 'get'] + self.add_auth_and_endpoint(argv) + argv.extend([secret_href]) + + stdout, stderr = self.issue_barbican_command(argv) + + if '4xx Client error: Not Found' in stderr: + return {} + + secret_data = self._prettytable_to_dict(stdout) + return secret_data + + def get_secret_payload(self, secret_href, raw=False): + """ Get a secret + + :param: the href to a secret + :param raw if True then add "-f value" to get raw payload (ie not + within a PrettyTable). If False then omit -f. + :return string representing the secret payload. + """ + argv = ['secret', 'get'] + self.add_auth_and_endpoint(argv) + argv.extend([secret_href]) + argv.extend(['--payload']) + if raw: + argv.extend(['-f', 'value']) + + stdout, stderr = self.issue_barbican_command(argv) + + if '4xx Client error: Not Found' in stderr: + return {} + + if raw: + secret = stdout.rstrip() + else: + secret_data = self._prettytable_to_dict(stdout) + secret = secret_data['Payload'] + + return secret + + def list_secrets(self): + """ List secrets + + :return: a list of secrets + """ + argv = ['secret', 'list'] + + self.add_auth_and_endpoint(argv) + stdout, stderr = self.issue_barbican_command(argv) + + secret_list = self._prettytable_to_list(stdout) + return secret_list + + def delete_all_created_secrets(self): + """ Delete all secrets that we created """ + for href in self.secret_hrefs_to_delete: + self.delete_secret(href)
\ No newline at end of file diff --git a/functionaltests/cli/v1/smoke/test_help.py b/functionaltests/cli/v1/smoke/test_help.py index b7b7e21..fda2a45 100644 --- a/functionaltests/cli/v1/smoke/test_help.py +++ b/functionaltests/cli/v1/smoke/test_help.py @@ -14,6 +14,7 @@ # limitations under the License. from functionaltests.cli.base import CmdLineTestCase +from functionaltests.cli.v1.behaviors import base_behaviors from functionaltests import utils from testtools import testcase @@ -23,6 +24,7 @@ class HelpTestCase(CmdLineTestCase): def setUp(self): super(HelpTestCase, self).setUp() + self.help_behaviors = base_behaviors.BaseBehaviors() def tearDown(self): super(HelpTestCase, self).tearDown() @@ -33,6 +35,6 @@ class HelpTestCase(CmdLineTestCase): }) @testcase.attr('positive') def test_help(self, argv): - stdout, stderr = self.issue_barbican_command(argv) + stdout, stderr = self.help_behaviors.issue_barbican_command(argv) self.assertIsNotNone(stdout, "{0} returned None".format(argv)) self.assertGreater(len(stdout), 0, "{0} invalid length".format(argv)) diff --git a/functionaltests/cli/v1/smoke/test_secret.py b/functionaltests/cli/v1/smoke/test_secret.py index 3b39225..1911458 100644 --- a/functionaltests/cli/v1/smoke/test_secret.py +++ b/functionaltests/cli/v1/smoke/test_secret.py @@ -14,6 +14,7 @@ # limitations under the License. from functionaltests.cli.base import CmdLineTestCase +from functionaltests.cli.v1.behaviors.secret_behaviors import SecretBehaviors from testtools import testcase @@ -21,157 +22,54 @@ class SecretTestCase(CmdLineTestCase): def setUp(self): super(SecretTestCase, self).setUp() - self.secret_hrefs_to_delete = [] - self.expected_payload = 'This is a top secret payload' + self.secret_behaviors = SecretBehaviors() + self.expected_payload = "Top secret payload for secret smoke tests" def tearDown(self): super(SecretTestCase, self).tearDown() - for href in self.secret_hrefs_to_delete: - self._delete_secret(href) + self.secret_behaviors.delete_all_created_secrets() @testcase.attr('positive') def test_secret_store(self): - secret_href = self._store_secret() + secret_href = self.secret_behaviors.store_secret() self.assertIsNotNone(secret_href) - secret = self._get_secret(secret_href) + secret = self.secret_behaviors.get_secret(secret_href) self.assertEqual(secret_href, secret['Secret href']) @testcase.attr('positive') def test_secret_list(self): secrets_to_create = 10 for _ in range(secrets_to_create): - self._store_secret() - secret_list = self._list_secrets() + self.secret_behaviors.store_secret() + secret_list = self.secret_behaviors.list_secrets() self.assertGreaterEqual(len(secret_list), secrets_to_create) @testcase.attr('positive') def test_secret_delete(self): - secret_href = self._store_secret() - self._delete_secret(secret_href) + secret_href = self.secret_behaviors.store_secret() + self.secret_behaviors.delete_secret(secret_href) - secret = self._get_secret(secret_href) + secret = self.secret_behaviors.get_secret(secret_href) self.assertEqual(0, len(secret)) @testcase.attr('positive') def test_secret_get(self): - secret_href = self._store_secret() - secret = self._get_secret(secret_href) + secret_href = self.secret_behaviors.store_secret() + secret = self.secret_behaviors.get_secret(secret_href) self.assertIsNotNone(secret) @testcase.attr('positive') def test_secret_get_payload(self): - secret_href = self._store_secret() - payload = self._get_secret_payload(secret_href) + secret_href = self.secret_behaviors.store_secret( + payload=self.expected_payload) + payload = self.secret_behaviors.get_secret_payload(secret_href) self.assertEqual(payload, self.expected_payload) @testcase.attr('positive') def test_secret_get_raw_payload(self): - secret_href = self._store_secret() - payload = self._get_secret_payload(secret_href, raw=True) + secret_href = self.secret_behaviors.store_secret( + payload=self.expected_payload) + payload = self.secret_behaviors.get_secret_payload(secret_href, + raw=True) self.assertEqual(payload, self.expected_payload) - - def _delete_secret(self, secret_href): - """ Delete a secret - - :param secret_href the href to the secret to delete - """ - argv = ['secret', 'delete'] - self.add_auth_and_endpoint(argv) - argv.extend([secret_href]) - - stdout, stderr = self.issue_barbican_command(argv) - self.assertEqual(0, len(stdout)) - self.assertEqual(0, len(stderr)) - - self.secret_hrefs_to_delete.remove(secret_href) - - def _store_secret(self): - """ Store (aka create) a secret - - :return: the href to the newly created secret - """ - argv = ['secret', 'store'] - self.add_auth_and_endpoint(argv) - argv.extend(['--payload', self.expected_payload]) - - stdout, stderr = self.issue_barbican_command(argv) - self.assertIsNotNone(stdout, 'no secret store string') - self.assertGreater(len(stdout), 0, 'invalid secret store length') - - secret_data = self._prettytable_to_secret(stdout) - self.assertIsNotNone(secret_data) - - secret_href = secret_data['Secret href'] - self.secret_hrefs_to_delete.append(secret_href) - return secret_href - - def _get_secret(self, secret_href): - """ Get a secret - - :param: the href to a secret - :return dict of secret values, or an empty dict if the secret - is not found. - """ - argv = ['secret', 'get'] - self.add_auth_and_endpoint(argv) - argv.extend([secret_href]) - - stdout, stderr = self.issue_barbican_command(argv) - - if '4xx Client error: Not Found' in stderr: - return {} - - self.assertIsNotNone(stdout, 'no secret get string') - self.assertGreater(len(stdout), 0, 'invalid secret get length') - - secret_data = self._prettytable_to_secret(stdout) - return secret_data - - def _get_secret_payload(self, secret_href, raw=False): - """ Get a secret - - :param: the href to a secret - :param raw if True then add "-f value" to get raw payload (ie not - within a PrettyTable). If False then omit -f. - :return string representing the secret payload. - """ - argv = ['secret', 'get'] - self.add_auth_and_endpoint(argv) - argv.extend([secret_href]) - argv.extend(['--payload']) - if raw: - argv.extend(['-f', 'value']) - - stdout, stderr = self.issue_barbican_command(argv) - - if '4xx Client error: Not Found' in stderr: - return {} - - self.assertIsNotNone(stdout, 'no secret get payload string') - self.assertGreater(len(stdout), 0, 'invalid secret get payload length') - - if raw: - secret = stdout.rstrip() - else: - secret_data = self._prettytable_to_secret(stdout) - secret = secret_data['Payload'] - - return secret - - def _list_secrets(self): - """ List secrets - - :return: a list of secrets - """ - argv = ['secret', 'list'] - - self.add_auth_and_endpoint(argv) - stdout, stderr = self.issue_barbican_command(argv) - self.assertIsNotNone(stdout, 'no secret list string') - self.assertGreater(len(stdout), 0, 'invalid secret list length') - - secret_list = self._prettytable_to_secret_list(stdout) - self.assertIsNotNone(secret_list) - - return secret_list |