Mercurial > bitten > bitten-test
changeset 196:b5f7d8a4035e
In preparation for supporting BDB XML transactions, move the report store backend selection away from using Trac extension points, and use a plain Python object instead of a component to represent a store backend.
author | cmlenz |
---|---|
date | Mon, 12 Sep 2005 21:59:14 +0000 |
parents | bd6234ed6ac5 |
children | d72c0587fae9 |
files | bitten/master.py bitten/store.py bitten/tests/store.py bitten/trac_ext/charts.py bitten/trac_ext/summarizers.py bitten/trac_ext/web_ui.py bitten/upgrades.py |
diffstat | 7 files changed, 99 insertions(+), 128 deletions(-) [+] |
line wrap: on
line diff
--- a/bitten/master.py +++ b/bitten/master.py @@ -20,7 +20,7 @@ from trac.env import Environment from bitten.model import BuildConfig, TargetPlatform, Build, BuildStep, BuildLog -from bitten.store import ReportStore +from bitten.store import get_store from bitten.util import archive, beep, xmlio log = logging.getLogger('bitten.master') @@ -109,7 +109,7 @@ def _cleanup_orphaned_builds(self): # Reset all in-progress builds db = self.env.get_db_cnx() - store = ReportStore(self.env) + store = get_store(self.env) for build in Build.select(self.env, status=Build.IN_PROGRESS, db=db): build.status = Build.PENDING build.slave = None @@ -120,7 +120,7 @@ for build_log in BuildLog.select(self.env, build=build.id): build_log.delete(db=db) build.update(db=db) - store.delete_reports(build=build) + store.delete(build=build) db.commit() def _cleanup_snapshots(self, when): @@ -369,9 +369,9 @@ message_elem.gettext())) build_log.insert(db=db) - store = ReportStore(self.env) + store = get_store(self.env) for report in elem.children('report'): - store.store_report(build, step, report) + store.store(build, step, report) def _build_completed(self, build, elem, timestamp_delta=None): log.info('Slave %s completed build %d ("%s" as of [%s]) with status %s', @@ -392,8 +392,8 @@ for step in BuildStep.select(self.env, build=build.id, db=db): step.delete(db=db) - store = ReportStore(self.env) - store.delete_reports(build=build) + store = get_store(self.env) + store.delete(build=build) build.slave = None build.started = 0
--- a/bitten/store.py +++ b/bitten/store.py @@ -13,48 +13,37 @@ from trac.core import * from bitten.util import xmlio -log = logging.getLogger('bitten.store') - - -class IReportStoreBackend(Interface): - def store_report(build, step, xml): - """Store the given report.""" +class ReportStore(object): - def retrieve_reports(build, step=None, type=None): - """Retrieve reports.""" + def delete(self, config=None, build=None, step=None, type=None): + raise NotImplementedError + + def query(self, xquery, config=None, build=None, step=None, + type=None): + raise NotImplementedError + + def retrieve(self, build, step=None, type=None): + raise NotImplementedError + + def store(self, build, step, xml): + raise NotImplementedError -class ReportStore(Component): - - backends = ExtensionPoint(IReportStoreBackend) - - def delete_reports(self, config=None, build=None, step=None, type=None): - backend = self._get_configured_backend() - return backend.delete_reports(config, build, step, type) - - def query_reports(self, xquery, config=None, build=None, step=None, - type=None): - backend = self._get_configured_backend() - return backend.query_reports(xquery, config, build, step, type) +class NullReportStore(ReportStore): - def retrieve_reports(self, build, step=None, type=None): - backend = self._get_configured_backend() - return backend.retrieve_reports(build, step, type) + def delete(self, config=None, build=None, step=None, type=None): + return - def store_report(self, build, step, xml): - assert xml.name == 'report' and 'type' in xml.attr - backend = self._get_configured_backend() - log.debug('Storing report of type "%s" in %s', xml.attr['type'], - backend.__class__.__name__) - backend.store_report(build, step, xml) + def query(self, xquery, config=None, build=None, step=None, + type=None): + return [] - def _get_configured_backend(self): - configured = self.config.get('bitten', 'report_store', 'BDBXMLBackend') - for backend in self.backends: - if backend.__class__.__name__ == configured: - return backend - raise TracError, 'Report store backend not available' + def retrieve(self, build, step=None, type=None): + return [] + + def store(self, build, step, xml): + return try: @@ -63,10 +52,9 @@ dbxml = None -class BDBXMLBackend(Component): - implements(IReportStoreBackend) +class BDBXMLReportStore(ReportStore): - indexes = [ + indices = [ ('config', 'node-metadata-equality-string'), ('build', 'node-metadata-equality-decimal'), ('step', 'node-metadata-equality-string'), @@ -111,42 +99,36 @@ return self._value.asString() - def __init__(self): - self.path = os.path.join(self.env.path, 'db', 'bitten.dbxml') + def __init__(self, path): + self.path = path + self.mgr = dbxml.XmlManager() + if not os.path.exists(path): + self.container = self.mgr.createContainer(self.path) + ctxt = self.mgr.createUpdateContext() + for name, index in self.indices: + self.container.addIndex('', name, index, ctxt) + else: + self.container = self.mgr.openContainer(self.path) - def delete_reports(self, config=None, build=None, step=None, type=None): - if dbxml is None: - log.warning('BDB XML not installed, cannot store report') - return - mgr = dbxml.XmlManager() - container = self._open_container(mgr, create=True) - ctxt = mgr.createUpdateContext() - for elem in self.query_reports('return $reports', config=config, - build=build, step=step, type=type): - container.deleteDocument(elem._value.asDocument(), ctxt) + def delete(self, config=None, build=None, step=None, type=None): + ctxt = self.mgr.createUpdateContext() + for elem in self.query('return $reports', config=config, build=build, + step=step, type=type): + self.container.deleteDocument(elem._value.asDocument(), ctxt) - def store_report(self, build, step, xml): - if dbxml is None: - log.warning('BDB XML not installed, cannot store report') - return - mgr = dbxml.XmlManager() - container = self._open_container(mgr, create=True) - ctxt = mgr.createUpdateContext() - doc = mgr.createDocument() + def store(self, build, step, xml): + assert xml.name == 'report' and 'type' in xml.attr + ctxt = self.mgr.createUpdateContext() + doc = self.mgr.createDocument() doc.setContent(str(xml)) doc.setMetaData('', 'config', dbxml.XmlValue(build.config)) doc.setMetaData('', 'build', dbxml.XmlValue(build.id)) doc.setMetaData('', 'step', dbxml.XmlValue(step.name)) - container.putDocument(doc, ctxt, dbxml.DBXML_GEN_NAME) + self.container.putDocument(doc, ctxt, dbxml.DBXML_GEN_NAME) - def query_reports(self, xquery, config=None, build=None, step=None, + def query(self, xquery, config=None, build=None, step=None, type=None): - if dbxml is None: - log.warning('BDB XML not installed, cannot query reports') - return - mgr = dbxml.XmlManager() - container = self._open_container(mgr) - ctxt = mgr.createQueryContext() + ctxt = self.mgr.createQueryContext() constraints = [] if config: @@ -162,21 +144,16 @@ if constraints: query += '[%s]' % ' and '.join(constraints) query += '\n' + xquery - self.log.debug('ExecutÃng XQuery: %s', query) - - results = mgr.query(query, ctxt) - for value in results: - yield BDBXMLBackend.XmlValueAdapter(value) - def retrieve_reports(self, build, step=None, type=None): - return self.query_reports('return $reports', build=build, step=step, - type=type) + results = self.mgr.query(query, ctxt) + for value in results: + yield BDBXMLReportStore.XmlValueAdapter(value) - def _open_container(self, mgr, create=False): - if create and not os.path.exists(self.path): - container = mgr.createContainer(self.path) - ctxt = mgr.createUpdateContext() - for name, index in self.indexes: - container.addIndex('', name, index, ctxt) - return container - return mgr.openContainer(self.path) + def retrieve(self, build, step=None, type=None): + return self.query('return $reports', build=build, step=step, type=type) + + +def get_store(env): + if dbxml is None: + return NullReportStore() + return BDBXMLReportStore(os.path.join(env.path, 'db', 'bitten.dbxml'))
--- a/bitten/tests/store.py +++ b/bitten/tests/store.py @@ -14,20 +14,19 @@ import unittest from trac.test import EnvironmentStub, Mock -from bitten.store import BDBXMLBackend +from bitten.store import BDBXMLReportStore from bitten.util import xmlio -class BDBXMLBackendTestCase(unittest.TestCase): +class BDBXMLReportStoreTestCase(unittest.TestCase): def setUp(self): - self.env = EnvironmentStub() - self.env.path = tempfile.mkdtemp('bitten-test') - os.mkdir(os.path.join(self.env.path, 'db')) - self.store = BDBXMLBackend(self.env) + self.path = os.path.join(tempfile.gettempdir(), 'bitten_test.dbxml') + self.store = BDBXMLReportStore(self.path) def tearDown(self): - shutil.rmtree(self.env.path) + self.store = None + os.unlink(self.path) def test_store_report(self): """ @@ -36,10 +35,9 @@ build = Mock(id=42, config='trunk') step = Mock(name='foo') xml = xmlio.Element('report', type='test')[xmlio.Element('dummy')] - self.store.store_report(build, step, xml) + self.store.store(build, step, xml) - self.assertEqual(1, len(list(self.store.retrieve_reports(build, step, - 'test')))) + self.assertEqual(1, len(list(self.store.retrieve(build, step, 'test')))) def test_retrieve_reports_for_step(self): """ @@ -49,15 +47,15 @@ build = Mock(id=42, config='trunk') step = Mock(name='foo') xml = xmlio.Element('report', type='test')[xmlio.Element('dummy')] - self.store.store_report(build, step, xml) + self.store.store(build, step, xml) xml = xmlio.Element('report', type='lint')[xmlio.Element('dummy')] - self.store.store_report(build, step, xml) + self.store.store(build, step, xml) other_step = Mock(name='bar') xml = xmlio.Element('report', type='test')[xmlio.Element('dummy')] - self.store.store_report(build, other_step, xml) + self.store.store(build, other_step, xml) - self.assertEqual(2, len(list(self.store.retrieve_reports(build, step)))) + self.assertEqual(2, len(list(self.store.retrieve(build, step)))) def test_retrieve_reports_for_build(self): """ @@ -68,23 +66,23 @@ step_foo = Mock(name='foo') step_bar = Mock(name='bar') xml = xmlio.Element('report', type='test')[xmlio.Element('dummy')] - self.store.store_report(build, step_foo, xml) + self.store.store(build, step_foo, xml) xml = xmlio.Element('report', type='lint')[xmlio.Element('dummy')] - self.store.store_report(build, step_bar, xml) + self.store.store(build, step_bar, xml) other_build = Mock(id=66, config='trunk') step_baz = Mock(name='foo') xml = xmlio.Element('report', type='test')[xmlio.Element('dummy')] - self.store.store_report(other_build, step_baz, xml) + self.store.store(other_build, step_baz, xml) - self.assertEqual(2, len(list(self.store.retrieve_reports(build)))) + self.assertEqual(2, len(list(self.store.retrieve(build)))) def suite(): suite = unittest.TestSuite() try: import dbxml - suite.addTest(unittest.makeSuite(BDBXMLBackendTestCase, 'test')) + suite.addTest(unittest.makeSuite(BDBXMLReportStoreTestCase, 'test')) except ImportError: print>>sys.stderr, 'Skipping unit tests for BDB XML backend' return suite
--- a/bitten/trac_ext/charts.py +++ b/bitten/trac_ext/charts.py @@ -13,7 +13,7 @@ from trac.core import * from trac.web import IRequestHandler from bitten.model import BuildConfig, Build -from bitten.store import ReportStore +from bitten.store import get_store from bitten.trac_ext.api import IReportChartGenerator from bitten.util import xmlio @@ -63,7 +63,7 @@ rev_map[str(build.id)] = (build.rev, datetime.fromtimestamp(build.rev_time)) - store = ReportStore(self.env) + store = get_store(self.env) xquery = """ for $report in $reports return @@ -78,7 +78,7 @@ # code tests = {} # Accumulated test numbers by revision - for test in store.query_reports(xquery, config=config, type='unittest'): + for test in store.query(xquery, config=config, type='unittest'): rev, rev_time = rev_map.get(test.attr['build']) if rev not in tests: tests[rev] = [rev_time, 0, 0] @@ -115,7 +115,7 @@ rev_map[str(build.id)] = (build.rev, datetime.fromtimestamp(build.rev_time)) - store = ReportStore(self.env) + store = get_store(self.env) xquery = """ for $report in $reports return @@ -134,7 +134,7 @@ # the Python code coverage = {} # Accumulated coverage info by revision - for test in store.query_reports(xquery, config=config, type='trace'): + for test in store.query(xquery, config=config, type='trace'): rev, rev_time = rev_map.get(test.attr['build']) if rev not in coverage: coverage[rev] = [rev_time, 0, 0]
--- a/bitten/trac_ext/summarizers.py +++ b/bitten/trac_ext/summarizers.py @@ -12,7 +12,7 @@ from trac.web.chrome import Chrome from trac.web.clearsilver import HDFWrapper from bitten.model import BuildConfig -from bitten.store import ReportStore +from bitten.store import get_store from bitten.trac_ext.api import IReportSummarizer @@ -30,9 +30,9 @@ def render_report_summary(self, req, build, step, report): hdf = HDFWrapper(loadpaths=Chrome(self.env).get_all_templates_dirs()) config = BuildConfig.fetch(self.env, name=build.config) - store = ReportStore(self.env) - results = store.query_reports(self.query, config=config, build=build, - step=step, type=self.report_type) + store = get_store(self.env) + results = store.query(self.query, config=config, build=build, step=step, + type=self.report_type) for idx, elem in enumerate(results): data = {} for name, value in elem.attr.items():
--- a/bitten/trac_ext/web_ui.py +++ b/bitten/trac_ext/web_ui.py @@ -19,7 +19,7 @@ add_link, add_stylesheet from trac.wiki import wiki_to_html from bitten.model import BuildConfig, TargetPlatform, Build, BuildStep, BuildLog -from bitten.store import ReportStore +from bitten.store import get_store from bitten.trac_ext.api import ILogFormatter, IReportSummarizer _status_label = {Build.IN_PROGRESS: 'in progress', @@ -494,8 +494,8 @@ for step in BuildStep.select(self.env, build=build.id, db=db): step.delete(db=db) - store = ReportStore(self.env) - store.delete_reports(build=build) + store = get_store(self.env) + store.delete(build=build) build.slave = None build.started = build.stopped = 0 @@ -526,9 +526,9 @@ types = summarizer.get_supported_report_types() summarizers.update(dict([(type, summarizer) for type in types])) - store = ReportStore(self.env) + store = get_store(self.env) reports = [] - for report in store.retrieve_reports(build, step): + for report in store.retrieve(build, step): report_type = report.attr['type'] summarizer = summarizers.get(report_type) if summarizer: @@ -622,9 +622,9 @@ req.hdf['build'] = {'id': build.id, 'href': self.env.href.build(build.config, build.id)} - store = ReportStore(self.env) + store = get_store(self.env) reports = [] - for report in store.retrieve_reports(build, step, report_type): + for report in store.retrieve(build, step, report_type): req.hdf['title'] = 'Build %d: %s' % (build.id, report_type) xml = report._node.toprettyxml(' ') if req.args.get('format') == 'xml':
--- a/bitten/upgrades.py +++ b/bitten/upgrades.py @@ -48,10 +48,6 @@ "NULL,label,description FROM old_config") def add_config_to_reports(env, db): - backend = env.config.get('bitten', 'report_store', 'BDBXMLBackend') - if backend != 'BDBXMLBackend': - return - from bitten.model import Build try: import dbxml