Merge remote-tracking branch 'upstream/master' into tox

This commit is contained in:
amitgandhinz 2014-08-01 15:12:11 -04:00
commit 2d65a41561
13 changed files with 238 additions and 131 deletions

View File

@ -35,6 +35,7 @@ _DRIVER_GROUP = 'drivers'
class Bootstrap(object):
"""Defines the CDN bootstrapper.
The bootstrap loads up drivers per a given configuration, and
@ -58,13 +59,10 @@ class Bootstrap(object):
provider_type = 'cdn.provider'
args = [self.conf]
try:
mgr = extension.ExtensionManager(namespace=provider_type,
invoke_on_load=True,
invoke_args=args)
return mgr
except RuntimeError as exc:
LOG.exception(exc)
mgr = extension.ExtensionManager(namespace=provider_type,
invoke_on_load=True,
invoke_args=args)
return mgr
@decorators.lazy_property(write=False)
def storage(self):

View File

@ -13,123 +13,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import functools
import msgpack
import cdn.openstack.common.log as logging
LOG = logging.getLogger(__name__)
def memoized_getattr(meth):
"""Memoizes attributes returned by __getattr__
It can be used to remember the results from
__getattr__ and reduce the debt of calling
it again when the same attribute is accessed.
This decorator memoizes attributes by setting
them on the object itself.
The wrapper returned by this decorator won't alter
the returned value.
:returns: A wrapper around the decorated method.
"""
@functools.wraps(meth)
def wrapper(self, method_name):
attr = meth(self, method_name)
setattr(self, method_name, attr)
return attr
return wrapper
def caches(keygen, ttl, cond=None):
"""Flags a getter method as being cached using oslo.cache.
It is assumed that the containing class defines an attribute
named `_cache` that is an instance of an oslo.cache backend.
The getter should raise an exception if the value can't be
loaded, which will skip the caching step. Otherwise, the
getter must return a value that can be encoded with
msgpack.
Note that you can also flag a remover method such that it
will purge an associated item from the cache, e.g.:
def project_cache_key(user, project=None):
return user + ':' + str(project)
class Project(object):
def __init__(self, db, cache):
self._db = db
self._cache = cache
@decorators.caches(project_cache_key, 60)
def get_project(self, user, project=None):
return self._db.get_project(user, project)
@get_project.purges
def del_project(self, user, project=None):
self._db.delete_project(user, project)
:param keygen: A static key generator function. This function
must accept the same arguments as the getter, sans `self`.
:param ttl: TTL for the cache entry, in seconds.
:param cond: Conditional for whether or not to cache the
value. Must be a function that takes a single value, and
returns True or False.
"""
def purges_prop(remover):
@functools.wraps(remover)
def wrapper(self, *args, **kwargs):
# First, purge from cache
key = keygen(*args, **kwargs)
del self._cache[key]
# Remove/delete from origin
remover(self, *args, **kwargs)
return wrapper
def prop(getter):
@functools.wraps(getter)
def wrapper(self, *args, **kwargs):
key = keygen(*args, **kwargs)
packed_value = self._cache.get(key)
if packed_value is None:
value = getter(self, *args, **kwargs)
# Cache new value if desired
if cond is None or cond(value):
# NOTE(kgriffs): Setting use_bin_type is essential
# for being able to distinguish between Unicode
# and binary strings when decoding; otherwise,
# both types are normalized to the MessagePack
# str format family.
packed_value = msgpack.packb(value, use_bin_type=True)
if not self._cache.set(key, packed_value, ttl):
LOG.warn('Failed to cache key: ' + key)
else:
# NOTE(kgriffs): unpackb does not default to UTF-8,
# so we have to explicitly ask for it.
value = msgpack.unpackb(packed_value, encoding='utf-8')
return value
wrapper.purges = purges_prop
return wrapper
return prop
def lazy_property(write=False, delete=True):
"""Creates a lazy property.

View File

@ -21,9 +21,9 @@ To run the tests
export CAFE_ROOT_LOG_PATH=~/.cdn/logs
export CAFE_TEST_LOG_PATH=~/.cdn/logs
3. Copy the tests.conf file to the path set by CAFE_CONFIG_FILE_PATH::
3. Copy the api.conf file to the path set by CAFE_CONFIG_FILE_PATH::
cp tests/api/etc/tests.conf ~/.cdn/tests.conf
cp tests/etc/api.conf ~/.cdn/tests.conf
4. Once you are ready to run the tests::

View File

@ -14,6 +14,7 @@
# limitations under the License.
import jsonschema
import os
from oslo.config import cfg
@ -35,6 +36,8 @@ class TestBase(fixtures.BaseTestFixture):
@classmethod
def setUpClass(cls):
cls.conf_file = 'cdn_mockdb.conf'
super(TestBase, cls).setUpClass()
cls.auth_config = config.AuthConfig()
@ -51,9 +54,14 @@ class TestBase(fixtures.BaseTestFixture):
deserialize_format='json')
cls.server_config = config.CDNServerConfig()
if cls.server_config.run_server:
conf = cfg.CONF
conf(project='cdn', prog='cdn')
conf_path = os.environ["CDN_TESTS_CONFIGS_DIR"]
config_file = os.path.join(conf_path, cls.conf_file)
conf = cfg.ConfigOpts()
conf(project='cdn', prog='cdn', args=[],
default_config_files=[config_file])
cdn_server = server.CDNServer()
cdn_server.start(conf)

View File

@ -16,7 +16,7 @@
import ddt
import uuid
from tests.api.utils import base
from tests.api import base
from tests.api.utils.schema import response

View File

@ -0,0 +1,4 @@
[drivers]
transport = nonexist
manager = nonexist
storage = nonexist

55
tests/etc/cdn_mockdb.conf Normal file
View File

@ -0,0 +1,55 @@
# By default, this should live in one of:
# ~/.cdn/cdn.conf
# /etc/cdn/cdn.conf
[DEFAULT]
# Show more verbose log output (sets INFO log level output)
;verbose = False
# Show debugging output in logs (sets DEBUG log level output)
;debug = False
# Log to this file
log_file = cdn.log
;auth_strategy =
# ================= Syslog Options ============================
# Send logs to syslog (/dev/log) instead of to file specified
# by `log_file`
;use_syslog = False
# Facility to use. If unset defaults to LOG_USER.
;syslog_log_facility = LOG_LOCAL0
# ================= Driver Options ============================
[drivers]
# Transport driver module (e.g., falcon, pecan)
transport = falcon
# Manager driver module (e.g. default)
manager = default
# Storage driver module (e.g., mongodb, sqlite, cassandra)
storage = mockdb
[drivers:transport:falcon]
bind = 0.0.0.0
port = 8888
[drivers:storage:mongodb]
uri = mongodb://localhost
database = cdn
[drivers:storage:cassandra]
cluster = "localhost"
keyspace = cdn
[drivers:storage:mockdb]
database = cdn
[drivers:provider:fastly]
apikey = "MYAPIKEY"

View File

@ -0,0 +1,50 @@
# Copyright (c) 2014 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 cdn.common import decorators
from tests.unit import base
class LazyPropertyTest(base.TestCase):
def test_delete(self):
original_value = object()
new_value = object()
class TestClass(object):
@decorators.lazy_property(write=True)
def var(self):
return original_value
test_class = TestClass()
setattr(test_class, 'var', new_value)
self.assertEqual(new_value, test_class.var)
del test_class.var
self.assertEqual(original_value, test_class.var)
def test_set(self):
original_value = object()
new_value = object()
class TestClass(object):
@decorators.lazy_property(write=True)
def var(self):
return original_value
test_class = TestClass()
setattr(test_class, 'var', new_value)
self.assertEqual(new_value, test_class.var)

View File

@ -0,0 +1,28 @@
# Copyright (c) 2014 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 oslo.config import cfg
from cdn.provider.mock import driver
from tests.unit import base
class MockProviderDriverTest(base.TestCase):
def setUp(self):
super(MockProviderDriverTest, self).setUp()
self.driver = driver.CDNProvider(cfg.CONF)
def test_mock_provider_driver_working(self):
self.assertTrue(self.driver.is_alive())

View File

@ -0,0 +1,29 @@
# Copyright (c) 2014 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 oslo.config import cfg
from cdn.storage.mockdb import driver
from tests.unit import base
class MockDBDriverTest(base.TestCase):
def test_mockdb_driver_working(self):
self.mockdb_driver = driver.MockDBStorageDriver(cfg.CONF)
self.assertTrue(self.mockdb_driver.is_alive())
self.assertTrue(self.mockdb_driver.service_database is None)
self.assertTrue(self.mockdb_driver.connection is None)
self.assertTrue(self.mockdb_driver.service_controller.session is None)

View File

@ -0,0 +1,52 @@
# Copyright (c) 2014 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 os
import mock
from oslo.config import cfg
from cdn import bootstrap
from tests.unit import base
class TestBootStrap(base.TestCase):
def test_boot_strap_successful(self):
tests_path = os.path.abspath(os.path.dirname(
os.path.dirname(__file__)))
conf_path = os.path.join(tests_path, 'etc', 'default_functional.conf')
cfg.CONF(args=[], default_config_files=[conf_path])
bootstrap_obj = bootstrap.Bootstrap(cfg.CONF)
mock_path = 'cdn.transport.pecan.driver.simple_server'
with mock.patch(mock_path) as mocked_module:
mock_server = mock.Mock()
mocked_module.make_server = mock.Mock(return_value=mock_server)
bootstrap_obj.run()
self.assertTrue(mock_server.serve_forever.called)
def test_boot_strap_when_exception(self):
tests_path = os.path.abspath(os.path.dirname(
os.path.dirname(__file__)))
conf_path = os.path.join(tests_path, 'etc', 'bootstrap_unit.conf')
cfg.CONF(args=[], default_config_files=[conf_path])
bootstrap_obj = bootstrap.Bootstrap(cfg.CONF)
self.assertTrue(bootstrap_obj.transport is None)
self.assertTrue(bootstrap_obj.manager is None)
self.assertTrue(bootstrap_obj.storage is None)

View File

@ -19,10 +19,10 @@ import mock
from oslo.config import cfg
from cdn.transport import pecan
from tests.unit.utils.base import UnitTestBase
from tests.unit import base
class PecanTransportDriverTest(UnitTestBase):
class PecanTransportDriverTest(base.TestCase):
def test_listen(self):
tests_path = os.path.abspath(os.path.dirname(