Commit 5014cc8d authored by Tres Seaver's avatar Tres Seaver

Return to 100% coverage.

Also, fix bugs uncovered thereby in processing float / tuple arguments.
parent 9e187359
...@@ -36,3 +36,6 @@ def convert_int(value): ...@@ -36,3 +36,6 @@ def convert_int(value):
if value in TRUETYPES: if value in TRUETYPES:
return 1 return 1
return int(value) return int(value)
def convert_tuple(value):
return tuple(value.split(','))
...@@ -13,6 +13,7 @@ import ZConfig ...@@ -13,6 +13,7 @@ import ZConfig
from zodburi.datatypes import convert_bytesize from zodburi.datatypes import convert_bytesize
from zodburi.datatypes import convert_int from zodburi.datatypes import convert_int
from zodburi.datatypes import convert_tuple
class Resolver(object): class Resolver(object):
...@@ -26,15 +27,14 @@ class Resolver(object): ...@@ -26,15 +27,14 @@ class Resolver(object):
unused = kw.copy() unused = kw.copy()
new = {} new = {}
convert_string = lambda s: s convert_string = lambda s: s
converters = ( converters = [
convert_int, (convert_int, self._int_args),
convert_string, (convert_string, self._string_args),
convert_bytesize) (convert_bytesize, self._bytesize_args),
args = ( (float, self._float_args),
self._int_args, (convert_tuple, self._tuple_args),
self._string_args, ]
self._bytesize_args) for convert, arg_names in converters:
for convert, arg_names in zip(converters, args):
for arg_name in arg_names: for arg_name in arg_names:
value = unused.pop(arg_name, None) value = unused.pop(arg_name, None)
if value is not None: if value is not None:
......
import cgi import cgi
import urlparse import urlparse
from ZODB.DemoStorage import DemoStorage from ZODB.DemoStorage import DemoStorage
from relstorage.adapters.postgresql import PostgreSQLAdapter
from relstorage.options import Options
from relstorage.storage import RelStorage
from .resolvers import Resolver from .resolvers import Resolver
try:
from relstorage.adapters.postgresql import PostgreSQLAdapter
from relstorage.options import Options
from relstorage.storage import RelStorage
except ImportError: #pragma NO COVER
pass
else:
# Not a real resolver, but we use interpret_kwargs
class PostgreSQLAdapterHelper(Resolver):
_int_args = ('connect_timeout', )
_string_args = ('ssl_mode', )
# Not a real resolver, but we use interpret_kwargs def __call__(self, parsed_uri, kw):
class PostgreSQLAdapterHelper(Resolver): dsn_args = [
_int_args = ('connect_timeout', ) ('dbname', parsed_uri.path[1:]),
_string_args = ('ssl_mode', ) ('user', parsed_uri.username),
('password', parsed_uri.password),
('host', parsed_uri.hostname),
('port', parsed_uri.port)
]
def __call__(self, parsed_uri, kw): kw, unused = self.interpret_kwargs(kw)
dsn_args = [ dsn_args.extend(kw.items())
('dbname', parsed_uri.path[1:]),
('user', parsed_uri.username),
('password', parsed_uri.password),
('host', parsed_uri.hostname),
('port', parsed_uri.port)
]
kw, unused = self.interpret_kwargs(kw) dsn = ' '.join("%s='%s'"%arg for arg in dsn_args)
dsn_args.extend(kw.items())
dsn = ' '.join("%s='%s'"%arg for arg in dsn_args) def factory(options):
return PostgreSQLAdapter(dsn=dsn, options=options)
return factory, unused
def factory(options):
return PostgreSQLAdapter(dsn=dsn, options=options)
return factory, unused
# The relstorage support is inspired by django-zodb.
# Oracle and mysql should be easily implementable from here
class RelStorageURIResolver(Resolver):
_int_args = ('poll_interval', 'cache_local_mb', 'commit_lock_timeout',
'commit_lock_id', 'read_only', 'shared_blob_dir',
'keep_history', 'pack_gc', 'pack_dry_run', 'strict_tpc',
'create', 'demostorage',)
_string_args = ('name', 'blob_dir', 'replica_conf',
'cache_module_name', 'cache_prefix',
'cache_delta_size_limit')
_bytesize_args = ('blob_cache_size', 'blob_cache_size_check',
'blob_cache_chunk_size')
_float_args = ('replica_timeout', 'pack_batch_timeout',
'pack_duty_cycle', 'pack_max_delay')
_tuple_args = ('cache_servers',)
# The relstorage support is inspired by django-zodb. def __init__(self, adapter_helper):
# Oracle and mysql should be easily implementable from here self.adapter_helper = adapter_helper
class RelStorageURIResolver(Resolver):
_int_args = ('poll_interval', 'cache_local_mb', 'commit_lock_timeout',
'commit_lock_id', 'read_only', 'shared_blob_dir',
'keep_history', 'pack_gc', 'pack_dry_run', 'strict_tpc',
'create', 'demostorage',)
_string_args = ('name', 'blob_dir', 'replica_conf', 'cache_module_name',
'cache_prefix', 'cache_delta_size_limit')
_bytesize_args = ('blob_cache_size', 'blob_cache_size_check',
'blob_cache_chunk_size')
_float_args = ('replica_timeout', 'pack_batch_timeout', 'pack_duty_cycle',
'pack_max_delay')
_tuple_args = ('cache_servers',)
def __init__(self, adapter_helper): def __call__(self, uri):
self.adapter_helper = adapter_helper uri = uri.replace('postgres://', 'http://', 1)
parsed_uri = urlparse.urlsplit(uri)
kw = dict(cgi.parse_qsl(parsed_uri.query))
def __call__(self, uri): adapter_factory, kw = self.adapter_helper(parsed_uri, kw)
uri = uri.replace('postgres://', 'http://', 1) kw, unused = self.interpret_kwargs(kw)
parsed_uri = urlparse.urlsplit(uri)
kw = dict(cgi.parse_qsl(parsed_uri.query))
adapter_factory, kw = self.adapter_helper(parsed_uri, kw) demostorage = kw.pop('demostorage', False)
kw, unused = self.interpret_kwargs(kw) options = Options(**kw)
demostorage = kw.pop('demostorage', False) def factory():
options = Options(**kw) adapter = adapter_factory(options)
storage = RelStorage(adapter=adapter, options=options)
if demostorage:
storage = DemoStorage(base=storage)
return storage
return factory, unused
def factory(): postgresql_resolver = RelStorageURIResolver(PostgreSQLAdapterHelper())
adapter = adapter_factory(options)
storage = RelStorage(adapter=adapter, options=options)
if demostorage:
storage = DemoStorage(base=storage)
return storage
return factory, unused
postgresql_resolver = RelStorageURIResolver(PostgreSQLAdapterHelper())
\ No newline at end of file
...@@ -10,20 +10,19 @@ class Base: ...@@ -10,20 +10,19 @@ class Base:
def test_bytesize_args(self): def test_bytesize_args(self):
resolver = self._makeOne() resolver = self._makeOne()
names = list(resolver._bytesize_args) names = sorted(resolver._bytesize_args)
kwargs = {} kwargs = {}
for name in names: for name in names:
kwargs[name] = '10MB' kwargs[name] = '10MB'
args = resolver.interpret_kwargs(kwargs)[0] args = resolver.interpret_kwargs(kwargs)[0]
keys = args.keys() keys = args.keys()
keys.sort() self.assertEqual(sorted(keys), names)
self.assertEqual(keys, names)
for name, value in args.items(): for name, value in args.items():
self.assertEqual(value, 10*1024*1024) self.assertEqual(value, 10*1024*1024)
def test_int_args(self): def test_int_args(self):
resolver = self._makeOne() resolver = self._makeOne()
names = list(resolver._int_args) names = sorted(resolver._int_args)
kwargs = {} kwargs = {}
for name in names: for name in names:
kwargs[name] = '10' kwargs[name] = '10'
...@@ -36,40 +35,37 @@ class Base: ...@@ -36,40 +35,37 @@ class Base:
def test_string_args(self): def test_string_args(self):
resolver = self._makeOne() resolver = self._makeOne()
names = list(resolver._string_args) names = sorted(resolver._string_args)
kwargs = {} kwargs = {}
for name in names: for name in names:
kwargs[name] = 'string' kwargs[name] = 'string'
args = resolver.interpret_kwargs(kwargs)[0] args = resolver.interpret_kwargs(kwargs)[0]
keys = args.keys() keys = args.keys()
keys.sort() self.assertEqual(sorted(keys), names)
self.assertEqual(keys, names)
for name, value in args.items(): for name, value in args.items():
self.assertEqual(value, 'string') self.assertEqual(value, 'string')
def test_float_args(self): def test_float_args(self):
resolver = self._makeOne() resolver = self._makeOne()
names = list(resolver._float_args) names = sorted(resolver._float_args)
kwargs = {} kwargs = {}
for name in names: for name in names:
kwargs[name] = '3.14' kwargs[name] = '3.14'
args = resolver.interpret_kwargs(kwargs)[0] args = resolver.interpret_kwargs(kwargs)[0]
keys = args.keys() keys = args.keys()
keys.sort() self.assertEqual(sorted(keys), names)
self.assertEqual(keys, names)
for name, value in args.items(): for name, value in args.items():
self.assertEqual(value, 3.14) self.assertEqual(value, 3.14)
def test_tuple_args(self): def test_tuple_args(self):
resolver = self._makeOne() resolver = self._makeOne()
names = list(resolver._tuple_args) names = sorted(resolver._tuple_args)
kwargs = {} kwargs = {}
for name in names: for name in names:
kwargs[name] = 'first,second,third' kwargs[name] = 'first,second,third'
args = resolver.interpret_kwargs(kwargs)[0] args = resolver.interpret_kwargs(kwargs)[0]
keys = args.keys() keys = args.keys()
keys.sort() self.assertEqual(sorted(keys), names)
self.assertEqual(keys, names)
for name, value in args.items(): for name, value in args.items():
self.assertEqual(value, ('first', 'second', 'third')) self.assertEqual(value, ('first', 'second', 'third'))
...@@ -412,101 +408,118 @@ class TestMappingStorageURIResolver(Base, unittest.TestCase): ...@@ -412,101 +408,118 @@ class TestMappingStorageURIResolver(Base, unittest.TestCase):
self.assertTrue(isinstance(storage, MappingStorage)) self.assertTrue(isinstance(storage, MappingStorage))
self.assertEqual(storage.__name__, 'storagename') self.assertEqual(storage.__name__, 'storagename')
try:
class TestPostgreSQLURIResolver(unittest.TestCase): from zodburi.resolvers_relstorage import RelStorageURIResolver
def _getTargetClass(self): except ImportError: #pragma NO COVER
from zodburi.resolvers_relstorage import RelStorageURIResolver pass
return RelStorageURIResolver else:
class TestPostgreSQLURIResolver(unittest.TestCase, Base):
def _makeOne(self): def _getTargetClass(self):
from zodburi.resolvers_relstorage import PostgreSQLAdapterHelper from zodburi.resolvers_relstorage import RelStorageURIResolver
klass = self._getTargetClass() return RelStorageURIResolver
return klass(PostgreSQLAdapterHelper())
def _makeOne(self):
def setUp(self): from zodburi.resolvers_relstorage import PostgreSQLAdapterHelper
# relstorage.options.Options is little more than a dict. klass = self._getTargetClass()
# We make it comparable to simplify the tests. return klass(PostgreSQLAdapterHelper())
from relstorage.options import Options
Options.__eq__ = lambda s, o: vars(s) == vars(o) def setUp(self):
# relstorage.options.Options is little more than a dict.
def test_bool_args(self): # We make it comparable to simplify the tests.
resolver = self._makeOne() from relstorage.options import Options
f = resolver.interpret_kwargs Options.__eq__ = lambda s, o: vars(s) == vars(o)
kwargs = f({'read_only':'1'})
self.assertEqual(kwargs[0], {'read_only':1}) def test_bool_args(self):
kwargs = f({'read_only':'true'}) resolver = self._makeOne()
self.assertEqual(kwargs[0], {'read_only':1}) f = resolver.interpret_kwargs
kwargs = f({'read_only':'on'}) kwargs = f({'read_only':'1'})
self.assertEqual(kwargs[0], {'read_only':1}) self.assertEqual(kwargs[0], {'read_only':1})
kwargs = f({'read_only':'off'}) kwargs = f({'read_only':'true'})
self.assertEqual(kwargs[0], {'read_only':0}) self.assertEqual(kwargs[0], {'read_only':1})
kwargs = f({'read_only':'no'}) kwargs = f({'read_only':'on'})
self.assertEqual(kwargs[0], {'read_only':0}) self.assertEqual(kwargs[0], {'read_only':1})
kwargs = f({'read_only':'false'}) kwargs = f({'read_only':'off'})
self.assertEqual(kwargs[0], {'read_only':0}) self.assertEqual(kwargs[0], {'read_only':0})
kwargs = f({'read_only':'no'})
@mock.patch('zodburi.resolvers_relstorage.PostgreSQLAdapter') self.assertEqual(kwargs[0], {'read_only':0})
@mock.patch('zodburi.resolvers_relstorage.RelStorage') kwargs = f({'read_only':'false'})
def test_call(self, RelStorage, PostgreSQLAdapter): self.assertEqual(kwargs[0], {'read_only':0})
from relstorage.options import Options
resolver = self._makeOne() @mock.patch('zodburi.resolvers_relstorage.PostgreSQLAdapter')
factory, dbkw = resolver('postgres://someuser:somepass@somehost:5432/somedb?read_only=1') @mock.patch('zodburi.resolvers_relstorage.RelStorage')
factory() def test_call(self, RelStorage, PostgreSQLAdapter):
from relstorage.options import Options
expected_options = Options(read_only=1) resolver = self._makeOne()
PostgreSQLAdapter.assert_called_once_with(dsn="dbname='somedb' user='someuser' password='somepass' " factory, dbkw = resolver(
"host='somehost' port='5432'", 'postgres://someuser:somepass@somehost:5432/somedb'
options=expected_options) '?read_only=1')
RelStorage.assert_called_once_with(adapter=PostgreSQLAdapter(), options=expected_options) factory()
@mock.patch('zodburi.resolvers_relstorage.PostgreSQLAdapter') expected_options = Options(read_only=1)
@mock.patch('zodburi.resolvers_relstorage.RelStorage') PostgreSQLAdapter.assert_called_once_with(
def test_call_adapter_options(self, RelStorage, PostgreSQLAdapter): dsn="dbname='somedb' user='someuser' password='somepass' "
from relstorage.options import Options "host='somehost' port='5432'", options=expected_options)
resolver = self._makeOne() RelStorage.assert_called_once_with(
factory, dbkw = resolver('postgres://someuser:somepass@somehost:5432/somedb?read_only=1' adapter=PostgreSQLAdapter(), options=expected_options)
'&connect_timeout=10')
factory() @mock.patch('zodburi.resolvers_relstorage.PostgreSQLAdapter')
@mock.patch('zodburi.resolvers_relstorage.RelStorage')
expected_options = Options(read_only=1) def test_call_adapter_options(self, RelStorage, PostgreSQLAdapter):
PostgreSQLAdapter.assert_called_once_with(dsn="dbname='somedb' user='someuser' password='somepass' " from relstorage.options import Options
"host='somehost' port='5432' connect_timeout='10'", resolver = self._makeOne()
options=expected_options) factory, dbkw = resolver(
RelStorage.assert_called_once_with(adapter=PostgreSQLAdapter(), options=expected_options) 'postgres://someuser:somepass@somehost:5432/somedb'
'?read_only=1&connect_timeout=10')
factory()
@mock.patch('zodburi.resolvers_relstorage.PostgreSQLAdapter')
@mock.patch('zodburi.resolvers_relstorage.RelStorage') expected_options = Options(read_only=1)
def test_invoke_factory_demostorage(self, RelStorage, PostgreSQLAdapter): PostgreSQLAdapter.assert_called_once_with(
from ZODB.DemoStorage import DemoStorage dsn="dbname='somedb' user='someuser' password='somepass' "
resolver = self._makeOne() "host='somehost' port='5432' connect_timeout='10'",
factory, dbkw = resolver('postgres://someuser:somepass@somehost:5432/somedb?read_only=1' options=expected_options)
'&demostorage=true') RelStorage.assert_called_once_with(
self.assertTrue(isinstance(factory(), DemoStorage)) adapter=PostgreSQLAdapter(), options=expected_options)
def test_dbargs(self):
resolver = self._makeOne() @mock.patch('zodburi.resolvers_relstorage.PostgreSQLAdapter')
factory, dbkw = resolver('postgres://someuser:somepass@somehost:5432/somedb?read_only=1&' @mock.patch('zodburi.resolvers_relstorage.RelStorage')
'connection_pool_size=1&' def test_invoke_factory_demostorage(self, RelStorage, PostgreSQLAdapter):
'connection_cache_size=1&' from ZODB.DemoStorage import DemoStorage
'database_name=dbname') resolver = self._makeOne()
self.assertEqual(dbkw, {'connection_pool_size': '1', factory, dbkw = resolver(
'connection_cache_size': '1', 'postgres://someuser:somepass@somehost:5432/somedb'
'database_name': 'dbname'}) '?read_only=1&demostorage=true')
self.assertTrue(isinstance(factory(), DemoStorage))
def test_dbargs(self):
resolver = self._makeOne()
factory, dbkw = resolver(
'postgres://someuser:somepass@somehost:5432/somedb'
'?read_only=1&connection_pool_size=1&connection_cache_size=1'
'&database_name=dbname')
self.assertEqual(dbkw, {'connection_pool_size': '1',
'connection_cache_size': '1',
'database_name': 'dbname'})
class TestEntryPoints(unittest.TestCase): class TestEntryPoints(unittest.TestCase):
def test_it(self): def test_it(self):
from pkg_resources import load_entry_point from pkg_resources import load_entry_point
from zodburi import resolvers, resolvers_relstorage from zodburi import resolvers
expected = [ expected = [
('memory', resolvers.MappingStorageURIResolver), ('memory', resolvers.MappingStorageURIResolver),
('zeo', resolvers.ClientStorageURIResolver), ('zeo', resolvers.ClientStorageURIResolver),
('file', resolvers.FileStorageURIResolver), ('file', resolvers.FileStorageURIResolver),
('zconfig', resolvers.ZConfigURIResolver), ('zconfig', resolvers.ZConfigURIResolver),
('postgres', resolvers_relstorage.RelStorageURIResolver),
] ]
try:
from zodburi.resolvers_relstorage import RelStorageURIResolver
except ImportError: #pragma NO COVER
pass
else:
expected.append(
('postgres', RelStorageURIResolver))
for name, cls in expected: for name, cls in expected:
target = load_entry_point('zodburi', 'zodburi.resolvers', name) target = load_entry_point('zodburi', 'zodburi.resolvers', name)
self.assertTrue(isinstance(target, cls)) self.assertTrue(isinstance(target, cls))
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment