aboutsummaryrefslogtreecommitdiffstats
path: root/keystone-moon/keystone/tests/unit/ksfixtures
diff options
context:
space:
mode:
Diffstat (limited to 'keystone-moon/keystone/tests/unit/ksfixtures')
-rw-r--r--keystone-moon/keystone/tests/unit/ksfixtures/__init__.py15
-rw-r--r--keystone-moon/keystone/tests/unit/ksfixtures/appserver.py79
-rw-r--r--keystone-moon/keystone/tests/unit/ksfixtures/cache.py36
-rw-r--r--keystone-moon/keystone/tests/unit/ksfixtures/database.py124
-rw-r--r--keystone-moon/keystone/tests/unit/ksfixtures/hacking.py489
-rw-r--r--keystone-moon/keystone/tests/unit/ksfixtures/key_repository.py34
-rw-r--r--keystone-moon/keystone/tests/unit/ksfixtures/temporaryfile.py29
7 files changed, 806 insertions, 0 deletions
diff --git a/keystone-moon/keystone/tests/unit/ksfixtures/__init__.py b/keystone-moon/keystone/tests/unit/ksfixtures/__init__.py
new file mode 100644
index 00000000..81b80298
--- /dev/null
+++ b/keystone-moon/keystone/tests/unit/ksfixtures/__init__.py
@@ -0,0 +1,15 @@
+# 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 keystone.tests.unit.ksfixtures.cache import Cache # noqa
+from keystone.tests.unit.ksfixtures.key_repository import KeyRepository # noqa
diff --git a/keystone-moon/keystone/tests/unit/ksfixtures/appserver.py b/keystone-moon/keystone/tests/unit/ksfixtures/appserver.py
new file mode 100644
index 00000000..ea1e6255
--- /dev/null
+++ b/keystone-moon/keystone/tests/unit/ksfixtures/appserver.py
@@ -0,0 +1,79 @@
+# Copyright 2013 OpenStack Foundation
+#
+# 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 __future__ import absolute_import
+
+import fixtures
+from oslo_config import cfg
+from paste import deploy
+
+from keystone.common import environment
+
+
+CONF = cfg.CONF
+
+MAIN = 'main'
+ADMIN = 'admin'
+
+
+class AppServer(fixtures.Fixture):
+ """A fixture for managing an application server instance.
+ """
+
+ def __init__(self, config, name, cert=None, key=None, ca=None,
+ cert_required=False, host='127.0.0.1', port=0):
+ super(AppServer, self).__init__()
+ self.config = config
+ self.name = name
+ self.cert = cert
+ self.key = key
+ self.ca = ca
+ self.cert_required = cert_required
+ self.host = host
+ self.port = port
+
+ def setUp(self):
+ super(AppServer, self).setUp()
+
+ app = deploy.loadapp(self.config, name=self.name)
+ self.server = environment.Server(app, self.host, self.port)
+ self._setup_SSL_if_requested()
+ self.server.start(key='socket')
+
+ # some tests need to know the port we ran on.
+ self.port = self.server.socket_info['socket'][1]
+ self._update_config_opt()
+
+ self.addCleanup(self.server.stop)
+
+ def _setup_SSL_if_requested(self):
+ # TODO(dstanek): fix environment.Server to take a SSLOpts instance
+ # so that the params are either always set or not
+ if (self.cert is not None and
+ self.ca is not None and
+ self.key is not None):
+ self.server.set_ssl(certfile=self.cert,
+ keyfile=self.key,
+ ca_certs=self.ca,
+ cert_required=self.cert_required)
+
+ def _update_config_opt(self):
+ """Updates the config with the actual port used."""
+ opt_name = self._get_config_option_for_section_name()
+ CONF.set_override(opt_name, self.port, group='eventlet_server')
+
+ def _get_config_option_for_section_name(self):
+ """Maps Paster config section names to port option names."""
+ return {'admin': 'admin_port', 'main': 'public_port'}[self.name]
diff --git a/keystone-moon/keystone/tests/unit/ksfixtures/cache.py b/keystone-moon/keystone/tests/unit/ksfixtures/cache.py
new file mode 100644
index 00000000..74566f1e
--- /dev/null
+++ b/keystone-moon/keystone/tests/unit/ksfixtures/cache.py
@@ -0,0 +1,36 @@
+# 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 fixtures
+
+from keystone.common import cache
+
+
+class Cache(fixtures.Fixture):
+ """A fixture for setting up and tearing down the cache between test cases.
+ """
+
+ def setUp(self):
+ super(Cache, self).setUp()
+
+ # NOTE(dstanek): We must remove the existing cache backend in the
+ # setUp instead of the tearDown because it defaults to a no-op cache
+ # and we want the configure call below to create the correct backend.
+
+ # NOTE(morganfainberg): The only way to reconfigure the CacheRegion
+ # object on each setUp() call is to remove the .backend property.
+ if cache.REGION.is_configured:
+ del cache.REGION.backend
+
+ # ensure the cache region instance is setup
+ cache.configure_cache_region(cache.REGION)
diff --git a/keystone-moon/keystone/tests/unit/ksfixtures/database.py b/keystone-moon/keystone/tests/unit/ksfixtures/database.py
new file mode 100644
index 00000000..15597539
--- /dev/null
+++ b/keystone-moon/keystone/tests/unit/ksfixtures/database.py
@@ -0,0 +1,124 @@
+# 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 functools
+import os
+import shutil
+
+import fixtures
+from oslo_config import cfg
+from oslo_db import options as db_options
+from oslo_db.sqlalchemy import migration
+
+from keystone.common import sql
+from keystone.common.sql import migration_helpers
+from keystone.tests import unit as tests
+
+
+CONF = cfg.CONF
+
+
+def run_once(f):
+ """A decorator to ensure the decorated function is only executed once.
+
+ The decorated function cannot expect any arguments.
+ """
+ @functools.wraps(f)
+ def wrapper():
+ if not wrapper.already_ran:
+ f()
+ wrapper.already_ran = True
+ wrapper.already_ran = False
+ return wrapper
+
+
+def _setup_database(extensions=None):
+ if CONF.database.connection != tests.IN_MEM_DB_CONN_STRING:
+ db = tests.dirs.tmp('test.db')
+ pristine = tests.dirs.tmp('test.db.pristine')
+
+ if os.path.exists(db):
+ os.unlink(db)
+ if not os.path.exists(pristine):
+ migration.db_sync(sql.get_engine(),
+ migration_helpers.find_migrate_repo())
+ for extension in (extensions or []):
+ migration_helpers.sync_database_to_version(extension=extension)
+ shutil.copyfile(db, pristine)
+ else:
+ shutil.copyfile(pristine, db)
+
+
+# NOTE(I159): Every execution all the options will be cleared. The method must
+# be called at the every fixture initialization.
+def initialize_sql_session():
+ # Make sure the DB is located in the correct location, in this case set
+ # the default value, as this should be able to be overridden in some
+ # test cases.
+ db_options.set_defaults(
+ CONF,
+ connection=tests.IN_MEM_DB_CONN_STRING)
+
+
+@run_once
+def _load_sqlalchemy_models():
+ """Find all modules containing SQLAlchemy models and import them.
+
+ This creates more consistent, deterministic test runs because tables
+ for all core and extension models are always created in the test
+ database. We ensure this by importing all modules that contain model
+ definitions.
+
+ The database schema during test runs is created using reflection.
+ Reflection is simply SQLAlchemy taking the model definitions for
+ all models currently imported and making tables for each of them.
+ The database schema created during test runs may vary between tests
+ as more models are imported. Importing all models at the start of
+ the test run avoids this problem.
+
+ """
+ keystone_root = os.path.normpath(os.path.join(
+ os.path.dirname(__file__), '..', '..', '..'))
+ for root, dirs, files in os.walk(keystone_root):
+ # NOTE(morganfainberg): Slice the keystone_root off the root to ensure
+ # we do not end up with a module name like:
+ # Users.home.openstack.keystone.assignment.backends.sql
+ root = root[len(keystone_root):]
+ if root.endswith('backends') and 'sql.py' in files:
+ # The root will be prefixed with an instance of os.sep, which will
+ # make the root after replacement '.<root>', the 'keystone' part
+ # of the module path is always added to the front
+ module_name = ('keystone.%s.sql' %
+ root.replace(os.sep, '.').lstrip('.'))
+ __import__(module_name)
+
+
+class Database(fixtures.Fixture):
+ """A fixture for setting up and tearing down a database.
+
+ """
+
+ def __init__(self, extensions=None):
+ super(Database, self).__init__()
+ self._extensions = extensions
+ initialize_sql_session()
+ _load_sqlalchemy_models()
+
+ def setUp(self):
+ super(Database, self).setUp()
+ _setup_database(extensions=self._extensions)
+
+ self.engine = sql.get_engine()
+ sql.ModelBase.metadata.create_all(bind=self.engine)
+ self.addCleanup(sql.cleanup)
+ self.addCleanup(sql.ModelBase.metadata.drop_all, bind=self.engine)
diff --git a/keystone-moon/keystone/tests/unit/ksfixtures/hacking.py b/keystone-moon/keystone/tests/unit/ksfixtures/hacking.py
new file mode 100644
index 00000000..47ef6b4b
--- /dev/null
+++ b/keystone-moon/keystone/tests/unit/ksfixtures/hacking.py
@@ -0,0 +1,489 @@
+# 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.
+
+# NOTE(morganfainberg) This file shouldn't have flake8 run on it as it has
+# code examples that will fail normal CI pep8/flake8 tests. This is expected.
+# The code has been moved here to ensure that proper tests occur on the
+# test_hacking_checks test cases.
+# flake8: noqa
+
+import fixtures
+
+
+class HackingCode(fixtures.Fixture):
+ """A fixture to house the various code examples for the keystone hacking
+ style checks.
+ """
+
+ mutable_default_args = {
+ 'code': """
+ def f():
+ pass
+
+ def f(a, b='', c=None):
+ pass
+
+ def f(bad=[]):
+ pass
+
+ def f(foo, bad=[], more_bad=[x for x in range(3)]):
+ pass
+
+ def f(foo, bad={}):
+ pass
+
+ def f(foo, bad={}, another_bad=[], fine=None):
+ pass
+
+ def f(bad=[]): # noqa
+ pass
+
+ def funcs(bad=dict(), more_bad=list(), even_more_bad=set()):
+ "creating mutables through builtins"
+
+ def funcs(bad=something(), more_bad=some_object.something()):
+ "defaults from any functions"
+
+ def f(bad=set(), more_bad={x for x in range(3)},
+ even_more_bad={1, 2, 3}):
+ "set and set comprehession"
+
+ def f(bad={x: x for x in range(3)}):
+ "dict comprehension"
+ """,
+ 'expected_errors': [
+ (7, 10, 'K001'),
+ (10, 15, 'K001'),
+ (10, 29, 'K001'),
+ (13, 15, 'K001'),
+ (16, 15, 'K001'),
+ (16, 31, 'K001'),
+ (22, 14, 'K001'),
+ (22, 31, 'K001'),
+ (22, 53, 'K001'),
+ (25, 14, 'K001'),
+ (25, 36, 'K001'),
+ (28, 10, 'K001'),
+ (28, 27, 'K001'),
+ (29, 21, 'K001'),
+ (32, 11, 'K001'),
+ ]}
+
+ comments_begin_with_space = {
+ 'code': """
+ # This is a good comment
+
+ #This is a bad one
+
+ # This is alright and can
+ # be continued with extra indentation
+ # if that's what the developer wants.
+ """,
+ 'expected_errors': [
+ (3, 0, 'K002'),
+ ]}
+
+ asserting_none_equality = {
+ 'code': """
+ class Test(object):
+
+ def test(self):
+ self.assertEqual('', '')
+ self.assertEqual('', None)
+ self.assertEqual(None, '')
+ self.assertNotEqual('', None)
+ self.assertNotEqual(None, '')
+ self.assertNotEqual('', None) # noqa
+ self.assertNotEqual(None, '') # noqa
+ """,
+ 'expected_errors': [
+ (5, 8, 'K003'),
+ (6, 8, 'K003'),
+ (7, 8, 'K004'),
+ (8, 8, 'K004'),
+ ]}
+
+ assert_no_translations_for_debug_logging = {
+ 'code': """
+ import logging
+ import logging as stlib_logging
+ from keystone.i18n import _
+ from keystone.i18n import _ as oslo_i18n
+ from keystone.openstack.common import log
+ from keystone.openstack.common import log as oslo_logging
+
+ # stdlib logging
+ L0 = logging.getLogger()
+ L0.debug(_('text'))
+ class C:
+ def __init__(self):
+ L0.debug(oslo_i18n('text', {}))
+
+ # stdlib logging w/ alias and specifying a logger
+ class C:
+ def __init__(self):
+ self.L1 = logging.getLogger(__name__)
+ def m(self):
+ self.L1.debug(
+ _('text'), {}
+ )
+
+ # oslo logging and specifying a logger
+ L2 = log.getLogger(__name__)
+ L2.debug(oslo_i18n('text'))
+
+ # oslo logging w/ alias
+ class C:
+ def __init__(self):
+ self.L3 = oslo_logging.getLogger()
+ self.L3.debug(_('text'))
+
+ # translation on a separate line
+ msg = _('text')
+ L2.debug(msg)
+
+ # this should not fail
+ if True:
+ msg = _('message %s') % X
+ L2.error(msg)
+ raise TypeError(msg)
+ if True:
+ msg = 'message'
+ L2.debug(msg)
+
+ # this should not fail
+ if True:
+ if True:
+ msg = _('message')
+ else:
+ msg = _('message')
+ L2.debug(msg)
+ raise Exception(msg)
+ """,
+ 'expected_errors': [
+ (10, 9, 'K005'),
+ (13, 17, 'K005'),
+ (21, 12, 'K005'),
+ (26, 9, 'K005'),
+ (32, 22, 'K005'),
+ (36, 9, 'K005'),
+ ]
+ }
+
+ oslo_namespace_imports = {
+ 'code': """
+ import oslo.utils
+ import oslo_utils
+ import oslo.utils.encodeutils
+ import oslo_utils.encodeutils
+ from oslo import utils
+ from oslo.utils import encodeutils
+ from oslo_utils import encodeutils
+
+ import oslo.serialization
+ import oslo_serialization
+ import oslo.serialization.jsonutils
+ import oslo_serialization.jsonutils
+ from oslo import serialization
+ from oslo.serialization import jsonutils
+ from oslo_serialization import jsonutils
+
+ import oslo.messaging
+ import oslo_messaging
+ import oslo.messaging.conffixture
+ import oslo_messaging.conffixture
+ from oslo import messaging
+ from oslo.messaging import conffixture
+ from oslo_messaging import conffixture
+
+ import oslo.db
+ import oslo_db
+ import oslo.db.api
+ import oslo_db.api
+ from oslo import db
+ from oslo.db import api
+ from oslo_db import api
+
+ import oslo.config
+ import oslo_config
+ import oslo.config.cfg
+ import oslo_config.cfg
+ from oslo import config
+ from oslo.config import cfg
+ from oslo_config import cfg
+
+ import oslo.i18n
+ import oslo_i18n
+ import oslo.i18n.log
+ import oslo_i18n.log
+ from oslo import i18n
+ from oslo.i18n import log
+ from oslo_i18n import log
+ """,
+ 'expected_errors': [
+ (1, 0, 'K333'),
+ (3, 0, 'K333'),
+ (5, 0, 'K333'),
+ (6, 0, 'K333'),
+ (9, 0, 'K333'),
+ (11, 0, 'K333'),
+ (13, 0, 'K333'),
+ (14, 0, 'K333'),
+ (17, 0, 'K333'),
+ (19, 0, 'K333'),
+ (21, 0, 'K333'),
+ (22, 0, 'K333'),
+ (25, 0, 'K333'),
+ (27, 0, 'K333'),
+ (29, 0, 'K333'),
+ (30, 0, 'K333'),
+ (33, 0, 'K333'),
+ (35, 0, 'K333'),
+ (37, 0, 'K333'),
+ (38, 0, 'K333'),
+ (41, 0, 'K333'),
+ (43, 0, 'K333'),
+ (45, 0, 'K333'),
+ (46, 0, 'K333'),
+ ],
+ }
+
+ dict_constructor = {
+ 'code': """
+ lower_res = {k.lower(): v for k, v in six.iteritems(res[1])}
+ fool = dict(a='a', b='b')
+ lower_res = dict((k.lower(), v) for k, v in six.iteritems(res[1]))
+ attrs = dict([(k, _from_json(v))])
+ dict([[i,i] for i in range(3)])
+ dict(({1:2}))
+ """,
+ 'expected_errors': [
+ (3, 0, 'K008'),
+ (4, 0, 'K008'),
+ (5, 0, 'K008'),
+ ]}
+
+
+class HackingLogging(fixtures.Fixture):
+
+ shared_imports = """
+ import logging
+ import logging as stlib_logging
+ from keystone.i18n import _
+ from keystone.i18n import _ as oslo_i18n
+ from keystone.i18n import _LC
+ from keystone.i18n import _LE
+ from keystone.i18n import _LE as error_hint
+ from keystone.i18n import _LI
+ from keystone.i18n import _LW
+ from keystone.openstack.common import log
+ from keystone.openstack.common import log as oslo_logging
+ """
+
+ examples = [
+ {
+ 'code': """
+ # stdlib logging
+ LOG = logging.getLogger()
+ LOG.info(_('text'))
+ class C:
+ def __init__(self):
+ LOG.warn(oslo_i18n('text', {}))
+ LOG.warn(_LW('text', {}))
+ """,
+ 'expected_errors': [
+ (3, 9, 'K006'),
+ (6, 17, 'K006'),
+ ],
+ },
+ {
+ 'code': """
+ # stdlib logging w/ alias and specifying a logger
+ class C:
+ def __init__(self):
+ self.L = logging.getLogger(__name__)
+ def m(self):
+ self.L.warning(
+ _('text'), {}
+ )
+ self.L.warning(
+ _LW('text'), {}
+ )
+ """,
+ 'expected_errors': [
+ (7, 12, 'K006'),
+ ],
+ },
+ {
+ 'code': """
+ # oslo logging and specifying a logger
+ L = log.getLogger(__name__)
+ L.error(oslo_i18n('text'))
+ L.error(error_hint('text'))
+ """,
+ 'expected_errors': [
+ (3, 8, 'K006'),
+ ],
+ },
+ {
+ 'code': """
+ # oslo logging w/ alias
+ class C:
+ def __init__(self):
+ self.LOG = oslo_logging.getLogger()
+ self.LOG.critical(_('text'))
+ self.LOG.critical(_LC('text'))
+ """,
+ 'expected_errors': [
+ (5, 26, 'K006'),
+ ],
+ },
+ {
+ 'code': """
+ LOG = log.getLogger(__name__)
+ # translation on a separate line
+ msg = _('text')
+ LOG.exception(msg)
+ msg = _LE('text')
+ LOG.exception(msg)
+ """,
+ 'expected_errors': [
+ (4, 14, 'K006'),
+ ],
+ },
+ {
+ 'code': """
+ LOG = logging.getLogger()
+
+ # ensure the correct helper is being used
+ LOG.warn(_LI('this should cause an error'))
+
+ # debug should not allow any helpers either
+ LOG.debug(_LI('this should cause an error'))
+ """,
+ 'expected_errors': [
+ (4, 9, 'K006'),
+ (7, 10, 'K005'),
+ ],
+ },
+ {
+ 'code': """
+ # this should not be an error
+ L = log.getLogger(__name__)
+ msg = _('text')
+ L.warn(msg)
+ raise Exception(msg)
+ """,
+ 'expected_errors': [],
+ },
+ {
+ 'code': """
+ L = log.getLogger(__name__)
+ def f():
+ msg = _('text')
+ L2.warn(msg)
+ something = True # add an extra statement here
+ raise Exception(msg)
+ """,
+ 'expected_errors': [],
+ },
+ {
+ 'code': """
+ LOG = log.getLogger(__name__)
+ def func():
+ msg = _('text')
+ LOG.warn(msg)
+ raise Exception('some other message')
+ """,
+ 'expected_errors': [
+ (4, 13, 'K006'),
+ ],
+ },
+ {
+ 'code': """
+ LOG = log.getLogger(__name__)
+ if True:
+ msg = _('text')
+ else:
+ msg = _('text')
+ LOG.warn(msg)
+ raise Exception(msg)
+ """,
+ 'expected_errors': [
+ ],
+ },
+ {
+ 'code': """
+ LOG = log.getLogger(__name__)
+ if True:
+ msg = _('text')
+ else:
+ msg = _('text')
+ LOG.warn(msg)
+ """,
+ 'expected_errors': [
+ (6, 9, 'K006'),
+ ],
+ },
+ {
+ 'code': """
+ LOG = log.getLogger(__name__)
+ msg = _LW('text')
+ LOG.warn(msg)
+ raise Exception(msg)
+ """,
+ 'expected_errors': [
+ (3, 9, 'K007'),
+ ],
+ },
+ {
+ 'code': """
+ LOG = log.getLogger(__name__)
+ msg = _LW('text')
+ LOG.warn(msg)
+ msg = _('something else')
+ raise Exception(msg)
+ """,
+ 'expected_errors': [],
+ },
+ {
+ 'code': """
+ LOG = log.getLogger(__name__)
+ msg = _LW('hello %s') % 'world'
+ LOG.warn(msg)
+ raise Exception(msg)
+ """,
+ 'expected_errors': [
+ (3, 9, 'K007'),
+ ],
+ },
+ {
+ 'code': """
+ LOG = log.getLogger(__name__)
+ msg = _LW('hello %s') % 'world'
+ LOG.warn(msg)
+ """,
+ 'expected_errors': [],
+ },
+ {
+ 'code': """
+ # this should not be an error
+ LOG = log.getLogger(__name__)
+ try:
+ something = True
+ except AssertionError as e:
+ LOG.warning(six.text_type(e))
+ raise exception.Unauthorized(e)
+ """,
+ 'expected_errors': [],
+ },
+ ]
diff --git a/keystone-moon/keystone/tests/unit/ksfixtures/key_repository.py b/keystone-moon/keystone/tests/unit/ksfixtures/key_repository.py
new file mode 100644
index 00000000..d1ac2ab4
--- /dev/null
+++ b/keystone-moon/keystone/tests/unit/ksfixtures/key_repository.py
@@ -0,0 +1,34 @@
+# 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 shutil
+import tempfile
+
+import fixtures
+
+from keystone.token.providers.fernet import utils
+
+
+class KeyRepository(fixtures.Fixture):
+ def __init__(self, config_fixture):
+ super(KeyRepository, self).__init__()
+ self.config_fixture = config_fixture
+
+ def setUp(self):
+ super(KeyRepository, self).setUp()
+ directory = tempfile.mkdtemp()
+ self.addCleanup(shutil.rmtree, directory)
+ self.config_fixture.config(group='fernet_tokens',
+ key_repository=directory)
+
+ utils.create_key_directory()
+ utils.initialize_key_repository()
diff --git a/keystone-moon/keystone/tests/unit/ksfixtures/temporaryfile.py b/keystone-moon/keystone/tests/unit/ksfixtures/temporaryfile.py
new file mode 100644
index 00000000..a4be06f8
--- /dev/null
+++ b/keystone-moon/keystone/tests/unit/ksfixtures/temporaryfile.py
@@ -0,0 +1,29 @@
+# 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
+import tempfile
+
+import fixtures
+
+
+class SecureTempFile(fixtures.Fixture):
+ """A fixture for creating a secure temp file."""
+
+ def setUp(self):
+ super(SecureTempFile, self).setUp()
+
+ _fd, self.file_name = tempfile.mkstemp()
+ # Make sure no file descriptors are leaked, close the unused FD.
+ os.close(_fd)
+ self.addCleanup(os.remove, self.file_name)