From 158698f1a69982a7a4d2f1425c92363b32203934 Mon Sep 17 00:00:00 2001 From: Holger Brunn Date: Mon, 4 Jun 2018 17:56:32 +0200 Subject: [PATCH] [ADD] runbot_preseed_database --- runbot_preseed_database/README.rst | 63 ++++++++ runbot_preseed_database/__init__.py | 4 + runbot_preseed_database/__manifest__.py | 20 +++ runbot_preseed_database/data/ir_cron.xml | 14 ++ runbot_preseed_database/models/__init__.py | 6 + .../models/runbot_branch.py | 24 +++ .../models/runbot_build.py | 149 ++++++++++++++++++ .../models/runbot_preseed_database_module.py | 10 ++ runbot_preseed_database/models/runbot_repo.py | 31 ++++ .../security/ir.model.access.csv | 3 + .../static/description/icon.png | Bin 0 -> 9455 bytes runbot_preseed_database/tests/__init__.py | 3 + .../tests/test_runbot_preseed_database.py | 82 ++++++++++ .../views/runbot_branch.xml | 16 ++ runbot_preseed_database/views/runbot_repo.xml | 16 ++ runbot_preseed_database/wizards/__init__.py | 3 + .../runbot_preseed_database_refresh.py | 138 ++++++++++++++++ .../runbot_preseed_database_refresh.xml | 32 ++++ 18 files changed, 614 insertions(+) create mode 100644 runbot_preseed_database/README.rst create mode 100644 runbot_preseed_database/__init__.py create mode 100644 runbot_preseed_database/__manifest__.py create mode 100644 runbot_preseed_database/data/ir_cron.xml create mode 100644 runbot_preseed_database/models/__init__.py create mode 100644 runbot_preseed_database/models/runbot_branch.py create mode 100644 runbot_preseed_database/models/runbot_build.py create mode 100644 runbot_preseed_database/models/runbot_preseed_database_module.py create mode 100644 runbot_preseed_database/models/runbot_repo.py create mode 100644 runbot_preseed_database/security/ir.model.access.csv create mode 100644 runbot_preseed_database/static/description/icon.png create mode 100644 runbot_preseed_database/tests/__init__.py create mode 100644 runbot_preseed_database/tests/test_runbot_preseed_database.py create mode 100644 runbot_preseed_database/views/runbot_branch.xml create mode 100644 runbot_preseed_database/views/runbot_repo.xml create mode 100644 runbot_preseed_database/wizards/__init__.py create mode 100644 runbot_preseed_database/wizards/runbot_preseed_database_refresh.py create mode 100644 runbot_preseed_database/wizards/runbot_preseed_database_refresh.xml diff --git a/runbot_preseed_database/README.rst b/runbot_preseed_database/README.rst new file mode 100644 index 00000000..26c3ec66 --- /dev/null +++ b/runbot_preseed_database/README.rst @@ -0,0 +1,63 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: https://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +=============================== +Preseed test database in runbot +=============================== + +This module allows you to have runbot use a database template that already has some modules installed. This allows for much faster builds in case you're only interested in a subset of the tests. + +Configuration +============= + +To configure this module, you need to: + +#. go to your repository (all builds in the repo) or a branch (just builds for this branch) +#. alternatively + - fill in a database name to be used as template. This database must exist in the cluster and be accessible for the user running runbot + - use the wizard to select a build to use to generate a template. This will also preselect all modules installed in the build's database minus the build's modules to test as the list of modules to preseed +#. when you use builds to generate template, review the refresh cronjob to move it to a time where regeneration won't interfere with your development. During refreshing, repos and branches with preseeded database will fall back to the empty database, so you will have slow builds in this period, not failing ones + +Usage +===== + +You will have to regenerate the database template from time if you don't use the build mechanism, and you should also take care to have one branch tested with a fresh database. This is meant to speedup builds for which most tests are irrelevant. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues +`_. In case of trouble, please +check there if your issue has already been reported. If you spotted it first, +help us smashing it by providing a detailed and welcomed feedback. + +Credits +======= + +Images +------ + +* Odoo Community Association: `Icon `_. + +Contributors +------------ + +* Holger Brunn + +Do not contact contributors directly about help with questions or problems concerning this addon, but use the `community mailing list `_ or the `appropriate specialized mailinglist `_ for help, and the bug tracker linked in `Bug Tracker`_ above for technical issues. + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +To contribute to this module, please visit https://odoo-community.org. diff --git a/runbot_preseed_database/__init__.py b/runbot_preseed_database/__init__.py new file mode 100644 index 00000000..467a5036 --- /dev/null +++ b/runbot_preseed_database/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2018 Therp BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from . import models +from . import wizards diff --git a/runbot_preseed_database/__manifest__.py b/runbot_preseed_database/__manifest__.py new file mode 100644 index 00000000..6f710466 --- /dev/null +++ b/runbot_preseed_database/__manifest__.py @@ -0,0 +1,20 @@ +# Copyright 2018 Therp BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +{ + "name": "Preseed test database in runbot", + "version": "11.0.1.0.0", + "author": "Therp BV,Odoo Community Association (OCA)", + "license": "AGPL-3", + "category": "Runbot", + "summary": "Allows to run tests with a partially initialized database", + "depends": [ + 'runbot', + ], + "data": [ + "data/ir_cron.xml", + "security/ir.model.access.csv", + "wizards/runbot_preseed_database_refresh.xml", + "views/runbot_branch.xml", + "views/runbot_repo.xml", + ], +} diff --git a/runbot_preseed_database/data/ir_cron.xml b/runbot_preseed_database/data/ir_cron.xml new file mode 100644 index 00000000..29f5c7b8 --- /dev/null +++ b/runbot_preseed_database/data/ir_cron.xml @@ -0,0 +1,14 @@ + + + + Regenerate preseed databases + code + + model._refresh_preseed_database() + + + + months + -1 + + diff --git a/runbot_preseed_database/models/__init__.py b/runbot_preseed_database/models/__init__.py new file mode 100644 index 00000000..01ef2d20 --- /dev/null +++ b/runbot_preseed_database/models/__init__.py @@ -0,0 +1,6 @@ +# Copyright 2018 Therp BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from . import runbot_repo +from . import runbot_build +from . import runbot_branch +from . import runbot_preseed_database_module diff --git a/runbot_preseed_database/models/runbot_branch.py b/runbot_preseed_database/models/runbot_branch.py new file mode 100644 index 00000000..dfab301c --- /dev/null +++ b/runbot_preseed_database/models/runbot_branch.py @@ -0,0 +1,24 @@ +# © 2018 Therp BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from odoo import api, fields, models + + +class RunbotBranch(models.Model): + _inherit = 'runbot.branch' + + preseed_database = fields.Char( + help='Fill in the name of a database to use as template for the all ' + 'build', copy=False, + ) + preseed_database_module_ids = fields.Many2many( + 'runbot.preseed.database.module', string='Modules to install', + copy=False, + ) + preseed_database_build_id = fields.Many2one( + 'runbot.build', string='Preseed database build', ondelete='restrict', + help='Select a build to use to generate the preseed database', + ) + + @api.constrains('preseed_database') + def _check_preseed_database(self): + self.env['runbot.repo']._check_preseed_database.__func__(self) diff --git a/runbot_preseed_database/models/runbot_build.py b/runbot_preseed_database/models/runbot_build.py new file mode 100644 index 00000000..74d042f1 --- /dev/null +++ b/runbot_preseed_database/models/runbot_build.py @@ -0,0 +1,149 @@ +# © 2018 Therp BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +import inspect +import os +import shutil +from psycopg2.extensions import AsIs +from odoo import api, fields, models +from odoo.addons.runbot.common import local_pgadmin_cursor + + +class RunbotBuild(models.Model): + _inherit = 'runbot.build' + + preseed_database = fields.Char( + compute=lambda self: [ + this.update({ + 'preseed_database': + this.branch_id.preseed_database or + this.branch_id.repo_id.preseed_database + }) + for this in self + ], + ) + preseed_database_build_id = fields.Many2one( + 'runbot.build', + compute=lambda self: [ + this.update({ + 'preseed_database_build_id': + this.branch_id.preseed_database_build_id or + this.branch_id.repo_id.preseed_database_build_id + }) + for this in self + ], + ) + preseed_repo_ids = fields.One2many( + 'runbot.repo', 'preseed_database_build_id', + ) + preseed_branch_ids = fields.One2many( + 'runbot.branch', 'preseed_database_build_id', + ) + + def _job_00_init(self, build, lock_path, log_path): + """Don't do a checkout for preseed builds""" + if build.preseed_repo_ids or build.preseed_branch_ids: + build._log('init', 'Skipping checkout for database refresh') + build._github_status() + return -2 + return super(RunbotBuild, self)._job_00_init( + build, lock_path, log_path + ) + + def _job_10_test_base(self, build, lock_path, log_path): + """No need for base tests for preseed builds""" + if build.preseed_repo_ids or build.preseed_branch_ids: + build._log('test_base', 'Skipping base test for database refresh') + return -2 + return super(RunbotBuild, self)._job_10_test_base( + build, lock_path, log_path + ) + + def _job_30_run(self, build, lock_path, log_path): + """Don't run preseed builds, this locks the database""" + if build.preseed_repo_ids or build.preseed_branch_ids: + build._log('test_base', 'Skipping running preseed build') + return -2 + return super(RunbotBuild, self)._job_30_run( + build, lock_path, log_path + ) + + def _local_pg_createdb(self, dbname): + """Use preseed database if applicable""" + if dbname.endswith('-base'): + # no need to do anything here + return super(RunbotBuild, self)._local_pg_createdb(dbname) + stack = inspect.stack() + # there should be a build in the callee, don't recurse through stack + build = stack[1][0].f_locals.get('build') + if ( + isinstance(build, models.BaseModel) and + build.preseed_database and + build.preseed_database_build_id != build and + ( + not build.preseed_database_build_id or + build.preseed_database_build_id.state == 'done' + ) + ): + build._log( + 'init', + 'Using %s as database template' % build.preseed_database + ) + with local_pgadmin_cursor() as cr: + cr.execute( + 'create database "%s" TEMPLATE "%s"', + (AsIs(dbname), AsIs(build.preseed_database)), + ) + if build.preseed_database_build_id: + # copy the build's filestore + template_filestore = build.preseed_database_build_id._path( + os.path.join( + 'datadir', 'filestore', build.preseed_database + ) + ) + build._log( + 'init', 'Copying filestore from %s' % template_filestore + ) + filestore = build._path(os.path.join('datadir', 'filestore')) + os.makedirs(filestore, exist_ok=True) + if os.path.exists(template_filestore): + shutil.copytree(template_filestore, os.path.join( + filestore, dbname + )) + else: + super(RunbotBuild, self)._local_pg_createdb(dbname) + + @api.multi + def _local_cleanup(self): + """Never clean up a preseed build""" + preseed_builds = self.env['runbot.build'].search([ + '|', + ('preseed_repo_ids', '!=', False), + ('preseed_branch_ids', '!=', False), + ]) + build2state = {build: build.state for build in preseed_builds} + # super deletes builds in state done + preseed_builds.write({'state': 'running'}) + super(RunbotBuild, self - preseed_builds)._local_cleanup() + for build, state in build2state.items(): + build.write({'state': state}) + + @api.multi + def reset(self): + self._reset_for_preseed() + return super(RunbotBuild, self).reset() + + @api.multi + def _reset_for_preseed(self): + for this in self: + repo_or_branch = this.preseed_branch_ids or this.preseed_repo_ids + if not repo_or_branch: + continue + this.write({ + 'modules': ','.join( + repo_or_branch.mapped('preseed_database_module_ids.name') + ), + }) + self.env['ir.logging'].search([ + ('build_id', '=', this.id), + ]).unlink() + this._reset() diff --git a/runbot_preseed_database/models/runbot_preseed_database_module.py b/runbot_preseed_database/models/runbot_preseed_database_module.py new file mode 100644 index 00000000..eff8ec7c --- /dev/null +++ b/runbot_preseed_database/models/runbot_preseed_database_module.py @@ -0,0 +1,10 @@ +# © 2018 Therp BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from odoo import fields, models + + +class RunbotPreseedDatabaseModule(models.Model): + _name = 'runbot.preseed.database.module' + _description = 'Preseed database module' + + name = fields.Char(required=True) diff --git a/runbot_preseed_database/models/runbot_repo.py b/runbot_preseed_database/models/runbot_repo.py new file mode 100644 index 00000000..09aabe15 --- /dev/null +++ b/runbot_preseed_database/models/runbot_repo.py @@ -0,0 +1,31 @@ +# © 2018 Therp BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +import psycopg2 +from odoo import api, fields, models + + +class RunbotRepo(models.Model): + _inherit = 'runbot.repo' + + preseed_database = fields.Char( + help='Fill in the name of a database to use as template for the all ' + 'build', copy=False, + ) + preseed_database_module_ids = fields.Many2many( + 'runbot.preseed.database.module', string='Modules to install', + help='Fill in some modules with long running tests like stock or ' + 'accounting. Do not fill in modules here that should be tested.', + copy=False, + ) + preseed_database_build_id = fields.Many2one( + 'runbot.build', string='Preseed database build', ondelete='restrict', + help='Select a build to use to generate the preseed database', + ) + + @api.constrains('preseed_database') + def _check_preseed_database(self): + for this in self: + if not this.preseed_database: + continue + connection = psycopg2.connect('dbname=%s' % this.preseed_database) + connection.close() diff --git a/runbot_preseed_database/security/ir.model.access.csv b/runbot_preseed_database/security/ir.model.access.csv new file mode 100644 index 00000000..9873176d --- /dev/null +++ b/runbot_preseed_database/security/ir.model.access.csv @@ -0,0 +1,3 @@ +"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" +access_runbot_preseed_database_module,access_runbot_preseed_database_module,model_runbot_preseed_database_module,runbot.group_runbot_admin,1,1,1,1 +access_runbot_preseed_database_module_user,access_runbot_preseed_database_module,model_runbot_preseed_database_module,runbot.group_user,1,0,0,0 diff --git a/runbot_preseed_database/static/description/icon.png b/runbot_preseed_database/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 diff --git a/runbot_preseed_database/tests/__init__.py b/runbot_preseed_database/tests/__init__.py new file mode 100644 index 00000000..0c771133 --- /dev/null +++ b/runbot_preseed_database/tests/__init__.py @@ -0,0 +1,3 @@ +# Copyright 2018 Therp BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from . import test_runbot_preseed_database diff --git a/runbot_preseed_database/tests/test_runbot_preseed_database.py b/runbot_preseed_database/tests/test_runbot_preseed_database.py new file mode 100644 index 00000000..f1c2c32f --- /dev/null +++ b/runbot_preseed_database/tests/test_runbot_preseed_database.py @@ -0,0 +1,82 @@ +# Copyright 2018 Therp BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +import os +import signal +import time +import logging +from openerp.tests.common import TransactionCase +_logger = logging.getLogger(__file__) + + +def run_build(build): + """run a build synchronously until it's finished""" + counter = 0 + while build.state not in ['done', 'running']: + counter += 1 + if counter % 5 == 0: + _logger.info('Still busy running build %d', build) + build._schedule() + if build.pid: + sig = (build.state == 'running') and signal.SIGKILL or 0 + try: + os.kill(build.pid, sig) + except OSError: + break + time.sleep(60) + + +class TestRunbotPreseedDatabase(TransactionCase): + def test_runbot_preseed_database(self): + repo = self.env['runbot.repo'].create({ + 'name': 'https://github.com/oca/ocb', + 'modules_auto': 'none', + 'modules': 'web', + }) + repo._update_git() + + branch = self.env['runbot.branch'].search([ + ('repo_id', '=', repo.id), + ('name', '=', 'refs/heads/11.0'), + ]) + build = self.env['runbot.build'].search([ + ('branch_id', '=', branch.id), + ]) + run_build(build) + cloned_build = build._force() + + # configure the repo to use this build as preseed build + wizard = self.env['runbot.preseed.database.refresh'].with_context( + active_model=repo._name, + active_id=repo.id, + ).new({ + 'build_id': build.id, + }) + wizard.onchange_build_id() + self.assertTrue(wizard.preseed_database) + wizard = self.env['runbot.preseed.database.refresh'].with_context( + active_model=repo._name, + active_id=repo.id, + ).create({ + 'build_id': build.id, + 'preseed_database': wizard.preseed_database, + }) + wizard.action_get_modules() + self.assertTrue(wizard.preseed_database_module_ids) + wizard.action_write_result() + build.refresh() + self.assertEqual(build.state, 'pending') + self.assertTrue(build.preseed_database) + self.assertTrue(build.preseed_repo_ids) + build.write({'state': 'done'}) + build._local_cleanup() + wizard._refresh_preseed_database() + self.assertEqual(build.state, 'pending') + + # let the build build + run_build(build) + # and be sure this uses our preseed database + run_build(cloned_build) + + build._kill() + cloned_build._kill() + repo.unlink() diff --git a/runbot_preseed_database/views/runbot_branch.xml b/runbot_preseed_database/views/runbot_branch.xml new file mode 100644 index 00000000..84edc3c1 --- /dev/null +++ b/runbot_preseed_database/views/runbot_branch.xml @@ -0,0 +1,16 @@ + + + + runbot.branch + + + + + + +