diff --git a/module_build_service/utils.py b/module_build_service/utils.py index 73ea89d8..9920a649 100644 --- a/module_build_service/utils.py +++ b/module_build_service/utils.py @@ -899,25 +899,15 @@ def record_component_builds(mmd, module, initial_batch=1, pkgref = mmd.xmd['mbs']['rpms'][pkg.name]['ref'] full_url = pkg.repository + "?#" + pkgref - - existing_build = models.ComponentBuild.query.filter_by( - module_id=module.id, package=pkg.name).first() - if existing_build: - if existing_build.state != koji.BUILD_STATES['COMPLETE']: - existing_build.state = None - session.add(existing_build) - else: - # XXX: what about components that were present in previous - # builds but are gone now (component reduction)? - build = models.ComponentBuild( - module_id=module.id, - package=pkg.name, - format="rpms", - scmurl=full_url, - batch=batch, - ref=pkgref - ) - session.add(build) + build = models.ComponentBuild( + module_id=module.id, + package=pkg.name, + format="rpms", + scmurl=full_url, + batch=batch, + ref=pkgref + ) + session.add(build) return batch @@ -958,6 +948,8 @@ def submit_module_build_from_scm(username, url, branch, allow_local_url=False, def submit_module_build(username, url, mmd, scm, optional_params=None): + import koji # Placed here to avoid py2/py3 conflicts... + # Import it here, because SCM uses utils methods # and fails to import them because of dep-chain. validate_mmd(mmd) @@ -978,8 +970,13 @@ def submit_module_build(username, url, mmd, scm, optional_params=None): raise ValidationError('You cannot change the module\'s "rebuild_strategy" when ' 'resuming a module build') log.debug('Resuming existing module build %r' % module) + # Reset all component builds that didn't complete + for component in module.component_builds: + if component.state and component.state != koji.BUILD_STATES['COMPLETE']: + component.state = None + db.session.add(component) module.username = username - module.transition(conf, models.BUILD_STATES["init"], + module.transition(conf, models.BUILD_STATES["wait"], "Resubmitted by %s" % username) module.batch = 0 log.info("Resumed existing module build in previous state %s" diff --git a/tests/staged_data/formatted_testmodule.yaml b/tests/staged_data/formatted_testmodule.yaml index d34a5353..5177bf3b 100644 --- a/tests/staged_data/formatted_testmodule.yaml +++ b/tests/staged_data/formatted_testmodule.yaml @@ -31,7 +31,7 @@ data: version: 20170109091357 xmd: mbs: - buildrequires: {base-runtime: {ref: ae993ba84f4bce554471382ccba917ef16265f11, stream: master, version: 20170315134803}} + buildrequires: {base-runtime: {ref: ae993ba84f4bce554471382ccba917ef16265f11, stream: master, version: 20170315134803, 'filtered_rpms': []}} commit: 7fea453bc362cc8e5aa41e129e689baea853653d scmurl: git://pkgs.stg.fedoraproject.org/modules/testmodule.git?#7fea453 document: modulemd diff --git a/tests/test_build/test_build.py b/tests/test_build/test_build.py index 98657bad..9a0ecb63 100644 --- a/tests/test_build/test_build.py +++ b/tests/test_build/test_build.py @@ -27,6 +27,7 @@ import os from os import path, mkdir from os.path import dirname from shutil import copyfile +from datetime import datetime from nose.tools import timed @@ -37,7 +38,7 @@ from module_build_service import db, models, conf, build_logs from mock import patch, PropertyMock -from tests import app, init_data, test_reuse_component_init_data +from tests import app, test_reuse_component_init_data, clean_database import json import itertools @@ -236,10 +237,7 @@ class TestBuild(unittest.TestCase): def setUp(self): GenericBuilder.register_backend_class(FakeModuleBuilder) self.client = app.test_client() - - init_data() - models.ModuleBuild.query.delete() - models.ComponentBuild.query.delete() + clean_database() filename = cassette_dir + self.id() self.vcr = vcr.use_cassette(filename) @@ -807,12 +805,63 @@ class TestBuild(unittest.TestCase): Tests that resuming the build works even when previous batches are already built. """ - FakeSCM(mocked_scm, 'testmodule', 'testmodule.yaml', - '620ec77321b2ea7b0d67d82992dda3e1d67055b4') + # Create a module in the failed state + build_one = models.ModuleBuild() + build_one.name = 'testmodule' + build_one.stream = 'master' + build_one.version = 1 + build_one.state = models.BUILD_STATES['failed'] + current_dir = os.path.dirname(__file__) + formatted_testmodule_yml_path = os.path.join( + current_dir, '..', 'staged_data', 'formatted_testmodule.yaml') + with open(formatted_testmodule_yml_path, 'r') as f: + build_one.modulemd = f.read() + build_one.koji_tag = 'module-testmodule-master-1' + build_one.scmurl = 'git://pkgs.stg.fedoraproject.org/modules/testmodule.git?#7fea453' + build_one.batch = models.BUILD_STATES['failed'] + build_one.owner = 'Homer J. Simpson' + build_one.time_submitted = datetime(2017, 2, 15, 16, 8, 18) + build_one.time_modified = datetime(2017, 2, 15, 16, 19, 35) + build_one.time_completed = datetime(2017, 2, 15, 16, 19, 35) + build_one.rebuild_strategy = 'changed-and-after' + # Successful component + component_one = models.ComponentBuild() + component_one.package = 'perl-Tangerine' + component_one.format = 'rpms' + component_one.scmurl = 'git://pkgs.stg.fedoraproject.org/rpms/perl-Tangerine.git?#f24' + component_one.state = koji.BUILD_STATES['COMPLETE'] + component_one.nvr = 'perl-Tangerine-0.23-1.module_testmodule_master_1' + component_one.batch = 2 + component_one.module_id = 1 + component_one.ref = '4ceea43add2366d8b8c5a622a2fb563b625b9abf' + # Failed component + component_two = models.ComponentBuild() + component_two.package = 'perl-List-Compare' + component_two.format = 'rpms' + component_two.scmurl = 'git://pkgs.stg.fedoraproject.org/rpms/perl-List-Compare.git?#f24' + component_two.state = koji.BUILD_STATES['FAILED'] + component_two.batch = 2 + component_two.module_id = 1 + # Component that isn't started yet + component_three = models.ComponentBuild() + component_three.package = 'tangerine' + component_three.format = 'rpms' + component_three.scmurl = 'git://pkgs.stg.fedoraproject.org/rpms/tangerine.git?#f24' + component_three.batch = 3 + component_three.module_id = 1 + db.session.add(build_one), + db.session.add(component_one) + db.session.add(component_two) + db.session.add(component_three) + db.session.commit() + db.session.expire_all() + + FakeSCM(mocked_scm, 'testmodule', 'testmodule.yaml', '7fea453') + # Resubmit the failed module rv = self.client.post('/module-build-service/1/module-builds/', data=json.dumps( {'branch': 'master', 'scmurl': 'git://pkgs.stg.fedoraproject.org/modules/' - 'testmodule.git?#68932c90de214d9d13feefbd35246a81b6cb8d49'})) + 'testmodule.git?#7fea453'})) data = json.loads(rv.data) module_build_id = data['id'] @@ -820,15 +869,17 @@ class TestBuild(unittest.TestCase): FakeModuleBuilder.BUILD_STATE = "BUILDING" FakeModuleBuilder.INSTANT_COMPLETE = True - # Set the components from batch 2 to COMPLETE - components = models.ComponentBuild.query.filter_by(module_id=module_build_id) - for c in components: - print(c) - if c.batch == 2: - c.state = koji.BUILD_STATES["COMPLETE"] - db.session.commit() + module_build = models.ModuleBuild.query.filter_by(id=module_build_id).one() + components = models.ComponentBuild.query.filter_by( + module_id=module_build_id, batch=2).order_by(models.ComponentBuild.id) + # Make sure the build went from failed to wait + self.assertEqual(module_build.state, models.BUILD_STATES["wait"]) + self.assertEqual(module_build.state_reason, 'Resubmitted by Homer J. Simpson') + # Make sure the state was reset on the failed component + self.assertIsNone(components[1].state) db.session.expire_all() + # Run the backend msgs = [] stop = module_build_service.scheduler.make_simple_stop_condition(db.session) module_build_service.scheduler.main(msgs, stop) @@ -874,10 +925,7 @@ class TestLocalBuild(unittest.TestCase): def setUp(self): GenericBuilder.register_backend_class(FakeModuleBuilder) self.client = app.test_client() - - init_data() - models.ModuleBuild.query.delete() - models.ComponentBuild.query.delete() + clean_database() filename = cassette_dir + self.id() self.vcr = vcr.use_cassette(filename) diff --git a/tests/test_utils/test_utils.py b/tests/test_utils/test_utils.py index 83f2d88e..3db26563 100644 --- a/tests/test_utils/test_utils.py +++ b/tests/test_utils/test_utils.py @@ -603,13 +603,13 @@ class TestUtils(unittest.TestCase): "Tom Brady", 'git://pkgs.stg.fedoraproject.org/modules/testmodule.git?#8fea453', 'master') - self.assertEqual(module_build.state, models.BUILD_STATES['init']) + self.assertEqual(module_build.state, models.BUILD_STATES['wait']) self.assertEqual(module_build.batch, 0) self.assertEqual(module_build.state_reason, "Resubmitted by Tom Brady") self.assertEqual(complete_component.state, koji.BUILD_STATES['COMPLETE']) - # These are still cancelled and failed until the init handler runs - self.assertEqual(failed_component.state, koji.BUILD_STATES['FAILED']) - self.assertEqual(canceled_component.state, koji.BUILD_STATES['CANCELED']) + # The failed/cancelled components are now stateless + self.assertIsNone(failed_component.state) + self.assertIsNone(canceled_component.state) @vcr.use_cassette( path.join(CASSETTES_DIR, ('tests.test_utils.TestUtils.'