Commit bd13e920 authored by Jim Fulton's avatar Jim Fulton

The databasesFrom... methods now support multiple databases.

Added an option to disallow cross-database references.
parent a996cb5b
......@@ -49,8 +49,15 @@ def databaseFromURL(url):
config, handler = ZConfig.loadConfig(getDbSchema(), url)
return databaseFromConfig(config.database)
def databaseFromConfig(section):
return section.open()
def databaseFromConfig(database_factories):
databases = {}
first = None
for factory in database_factories:
db = factory.open(databases)
if first is None:
first = db
return first
def storageFromString(s):
return storageFromFile(StringIO(s))
......@@ -93,8 +100,16 @@ class ZODBDatabase(BaseConfig):
section = self.config
storage = section.storage.open()
options = {}
if section.pool_timeout is not None:
options['pool_timeout'] = section.pool_timeout
def _option(name, oname=None):
v = getattr(section, name)
if v is not None:
if oname is None:
oname = name
options[oname] = v
_option('pool_timeout')
_option('allow_implicit_cross_references', 'xrefs')
try:
return ZODB.DB(
......@@ -106,7 +121,7 @@ class ZODBDatabase(BaseConfig):
historical_cache_size=section.historical_cache_size,
historical_cache_size_bytes=section.historical_cache_size_bytes,
historical_timeout=section.historical_timeout,
database_name=section.database_name,
database_name=section.database_name or self.name or '',
databases=databases,
**options)
except:
......
......@@ -2,6 +2,7 @@
<import package="ZODB"/>
<section type="ZODB.database" name="*" attribute="database"/>
<multisection type="ZODB.database" name="*" attribute="database"
required="yes" />
</schema>
......@@ -12,23 +12,26 @@
#
##############################################################################
import os
import transaction
import doctest
import tempfile
import unittest
import ZEO.ClientStorage
import transaction
import ZODB.config
import ZODB.POSException
import ZODB.tests.util
from zope.testing import doctest
from ZODB.POSException import ReadOnlyError
class ConfigTestBase(ZODB.tests.util.TestCase):
class ConfigTestBase(unittest.TestCase):
def _opendb(self, s):
return ZODB.config.databaseFromString(s)
def tearDown(self):
if getattr(self, "storage", None) is not None:
self.storage.cleanup()
def _test(self, s):
db = self._opendb(s)
self.storage = db.storage
self.storage = db._storage
# Do something with the database to make sure it works
cn = db.open()
rt = cn.root()
......@@ -56,26 +59,28 @@ class ZODBConfigTest(ConfigTestBase):
""")
def test_file_config1(self):
path = tempfile.mktemp()
self._test(
"""
<zodb>
<filestorage>
path Data.fs
path %s
</filestorage>
</zodb>
""")
""" % path)
def test_file_config2(self):
path = tempfile.mktemp()
cfg = """
<zodb>
<filestorage>
path Data.fs
path %s
create false
read-only true
</filestorage>
</zodb>
"""
self.assertRaises(ZODB.POSException.ReadOnlyError, self._test, cfg)
""" % path
self.assertRaises(ReadOnlyError, self._test, cfg)
def test_demo_config(self):
cfg = """
......@@ -110,54 +115,116 @@ class ZEOConfigTest(ConfigTestBase):
</zodb>
"""
config, handle = ZConfig.loadConfigFile(getDbSchema(), StringIO(cfg))
self.assertEqual(config.database.config.storage.config.blob_dir,
self.assertEqual(config.database[0].config.storage.config.blob_dir,
None)
self.assertRaises(ClientDisconnected, self._test, cfg)
cfg = """
<zodb>
<zeoclient>
blob-dir blobs
blob-dir /tmp
server localhost:56897
wait false
</zeoclient>
</zodb>
"""
config, handle = ZConfig.loadConfigFile(getDbSchema(), StringIO(cfg))
self.assertEqual(
os.path.abspath(config.database.config.storage.config.blob_dir),
os.path.abspath('blobs'))
self.assertEqual(config.database[0].config.storage.config.blob_dir,
'/tmp')
self.assertRaises(ClientDisconnected, self._test, cfg)
def db_connection_pool_timeout():
def database_xrefs_config():
r"""
>>> db = ZODB.config.databaseFromString(
... "<zodb>\n<mappingstorage>\n</mappingstorage>\n</zodb>\n")
>>> db.xrefs
True
>>> db = ZODB.config.databaseFromString(
... "<zodb>\nallow-implicit-cross-references true\n"
... "<mappingstorage>\n</mappingstorage>\n</zodb>\n")
>>> db.xrefs
True
>>> db = ZODB.config.databaseFromString(
... "<zodb>\nallow-implicit-cross-references false\n"
... "<mappingstorage>\n</mappingstorage>\n</zodb>\n")
>>> db.xrefs
False
"""
Test that the database pool timeout option works:
def multi_atabases():
r"""If there are multiple codb sections -> multidatabase
>>> db = ZODB.config.databaseFromString('''
... <zodb>
... <mappingstorage/>
... <mappingstorage>
... </mappingstorage>
... </zodb>
... <zodb Foo>
... <mappingstorage>
... </mappingstorage>
... </zodb>
... <zodb>
... database-name Bar
... <mappingstorage>
... </mappingstorage>
... </zodb>
... ''')
>>> db.pool._timeout == 1<<31
>>> sorted(db.databases)
['', 'Bar', 'foo']
>>> db.database_name
''
>>> db.databases[db.database_name] is db
True
>>> db.databases['foo'] is not db
True
>>> db.databases['Bar'] is not db
True
>>> db.databases['Bar'] is not db.databases['foo']
True
>>> db = ZODB.config.databaseFromString('''
Can't have repeats:
>>> ZODB.config.databaseFromString('''
... <zodb 1>
... <mappingstorage>
... </mappingstorage>
... </zodb>
... <zodb 1>
... <mappingstorage>
... </mappingstorage>
... </zodb>
... <zodb 1>
... <mappingstorage>
... </mappingstorage>
... </zodb>
... ''') # doctest: +NORMALIZE_WHITESPACE
Traceback (most recent call last):
...
ConfigurationSyntaxError:
section names must not be re-used within the same container:'1' (line 9)
>>> ZODB.config.databaseFromString('''
... <zodb>
... pool-timeout 600
... <mappingstorage/>
... <mappingstorage>
... </mappingstorage>
... </zodb>
... ''')
>>> db.pool._timeout == 600
True
... <zodb>
... <mappingstorage>
... </mappingstorage>
... </zodb>
... ''') # doctest: +NORMALIZE_WHITESPACE
Traceback (most recent call last):
...
ValueError: database_name '' already in databases
"""
def test_suite():
suite = unittest.TestSuite()
suite.addTest(doctest.DocTestSuite())
suite.addTest(unittest.makeSuite(ZODBConfigTest))
suite.addTest(unittest.makeSuite(ZEOConfigTest))
suite.addTest(doctest.DocTestSuite())
return suite
......
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