def test_add_default_modules_request_failed(mock_get_dm): """ Test that an exception is raised when the call to _get_default_modules failed. """ clean_database() make_module_in_db("python:3:12345:1") make_module_in_db("nodejs:11:2345:2") mmd = load_mmd(read_staged_data("formatted_testmodule.yaml")) xmd_brs = mmd.get_xmd()["mbs"]["buildrequires"] assert set(xmd_brs.keys()) == {"platform"} platform = ModuleBuild.get_build_from_nsvc( db_session, "platform", xmd_brs["platform"]["stream"], xmd_brs["platform"]["version"], xmd_brs["platform"]["context"], ) assert platform platform_mmd = platform.mmd() platform_xmd = mmd.get_xmd() platform_xmd["mbs"]["use_default_modules"] = True platform_mmd.set_xmd(platform_xmd) platform.modulemd = mmd_to_str(platform_mmd) db_session.commit() expected_error = "some error" mock_get_dm.side_effect = ValueError(expected_error) with pytest.raises(ValueError, match=expected_error): default_modules.add_default_modules(mmd)
def test_add_default_modules_not_linked(mock_get_dm): """ Test that no default modules are added when they aren't linked from the base module. """ clean_database() mmd = load_mmd(read_staged_data("formatted_testmodule.yaml")) assert set(mmd.get_xmd()["mbs"]["buildrequires"].keys()) == {"platform"} default_modules.add_default_modules(mmd) assert set(mmd.get_xmd()["mbs"]["buildrequires"].keys()) == {"platform"} mock_get_dm.assert_not_called()
def test_add_default_modules_platform_not_available(require_empty_database): """ Test that an exception is raised when the platform module that is buildrequired is missing. This error should never occur in practice. """ mmd = load_mmd(read_staged_data("formatted_testmodule.yaml")) expected_error = "Failed to retrieve the module platform:f28:3:00000000 from the database" with pytest.raises(RuntimeError, match=expected_error): default_modules.add_default_modules(mmd)
def test_add_default_modules(mock_get_dm, mock_hc, require_platform_and_default_arch): """ Test that default modules present in the database are added, and the others are ignored. """ mmd = load_mmd(read_staged_data("formatted_testmodule.yaml")) xmd_brs = mmd.get_xmd()["mbs"]["buildrequires"] assert set(xmd_brs.keys()) == {"platform"} platform = ModuleBuild.get_build_from_nsvc( db_session, "platform", xmd_brs["platform"]["stream"], xmd_brs["platform"]["version"], xmd_brs["platform"]["context"], ) assert platform platform_mmd = platform.mmd() platform_xmd = mmd.get_xmd() platform_xmd["mbs"]["use_default_modules"] = True platform_mmd.set_xmd(platform_xmd) platform.modulemd = mmd_to_str(platform_mmd) dependencies = [{ "requires": { "platform": ["f28"] }, "buildrequires": { "platform": ["f28"] } }] make_module_in_db("python:3:12345:1", base_module=platform, dependencies=dependencies) make_module_in_db("nodejs:11:2345:2", base_module=platform, dependencies=dependencies) db_session.commit() mock_get_dm.return_value = { "nodejs": "11", "python": "3", "ruby": "2.6", } defaults_added = default_modules.add_default_modules(mmd) # Make sure that the default modules were added. ruby:2.6 will be ignored since it's not in # the database assert set(mmd.get_xmd()["mbs"]["buildrequires"].keys()) == { "nodejs", "platform", "python" } mock_get_dm.assert_called_once_with( "f28", "https://pagure.io/releng/fedora-module-defaults.git", ) assert "ursine_rpms" not in mmd.get_xmd()["mbs"] assert defaults_added is True
def test_add_default_modules_compatible_platforms(mock_get_dm): """ Test that default modules built against compatible base module streams are added. """ clean_database(add_platform_module=False) # Create compatible base modules. mmd = load_mmd(read_staged_data("platform")) for stream in ["f27", "f28"]: mmd = mmd.copy("platform", stream) # Set the virtual stream to "fedora" to make these base modules compatible. xmd = mmd.get_xmd() xmd["mbs"]["virtual_streams"] = ["fedora"] xmd["mbs"]["use_default_modules"] = True mmd.set_xmd(xmd) import_mmd(db_session, mmd) mmd = load_mmd(read_staged_data("formatted_testmodule.yaml")) xmd_brs = mmd.get_xmd()["mbs"]["buildrequires"] assert set(xmd_brs.keys()) == {"platform"} platform_f27 = ModuleBuild.get_build_from_nsvc( db_session, "platform", "f27", "3", "00000000") assert platform_f27 # Create python default module which requires platform:f27 and therefore cannot be used # as default module for platform:f28. dependencies = [ {"requires": {"platform": ["f27"]}, "buildrequires": {"platform": ["f27"]}}] make_module_in_db("python:3:12345:1", base_module=platform_f27, dependencies=dependencies) # Create nodejs default module which requries any platform stream and therefore can be used # as default module for platform:f28. dependencies[0]["requires"]["platform"] = [] make_module_in_db("nodejs:11:2345:2", base_module=platform_f27, dependencies=dependencies) db_session.commit() mock_get_dm.return_value = { "nodejs": "11", "python": "3", "ruby": "2.6", } defaults_added = default_modules.add_default_modules(mmd) # Make sure that the default modules were added. ruby:2.6 will be ignored since it's not in # the database assert set(mmd.get_xmd()["mbs"]["buildrequires"].keys()) == {"nodejs", "platform"} mock_get_dm.assert_called_once_with( "f28", "https://pagure.io/releng/fedora-module-defaults.git", ) assert defaults_added is True
def init(msg_id, module_build_id, module_build_state): """Called whenever a module enters the 'init' state. :param str msg_id: the original id of the message being handled, which is received from message bus. :param int module_build_id: the module build id. :param int module_build_state: the module build state. """ build = models.ModuleBuild.get_by_id(db_session, module_build_id) state_init = models.BUILD_STATES["init"] if module_build_state == state_init and build.state != state_init: log.warning("Module build %r has moved to %s state already.", build, models.INVERSE_BUILD_STATES[build.state]) log.warning( "Ignore this message %s. Is there something wrong with the frontend" " that sends duplicate messages?", msg_id) return # for MockModuleBuilder, set build logs dir to mock results dir # before build_logs start if conf.system == "mock": build_tag_name = generate_module_build_koji_tag(build) mock_resultsdir = os.path.join(conf.mock_resultsdir, build_tag_name) if not os.path.exists(mock_resultsdir): os.makedirs(mock_resultsdir) build_logs.build_logs_dir = mock_resultsdir build_logs.start(db_session, build) log.info("Start to handle %s which is in init state.", build.mmd().get_nsvc()) error_msg = "" failure_reason = "unspec" try: mmd = build.mmd() record_module_build_arches(mmd, build) arches = [arch.name for arch in build.arches] defaults_added = add_default_modules(mmd) # Get map of packages that have SRPM overrides srpm_overrides = get_module_srpm_overrides(build) # Format the modulemd by putting in defaults and replacing streams that # are branches with commit hashes format_mmd(mmd, build.scmurl, build, db_session, srpm_overrides) record_component_builds(mmd, build) # The ursine.handle_stream_collision_modules is Koji specific. # It is also run only when Ursa Prime is not enabled for the base # module (`if not defaults_added`). if conf.system in ["koji", "test"] and not defaults_added: handle_stream_collision_modules(mmd) # Sets xmd["mbs"]["ursine_rpms"] with RPMs from the buildrequired base modules which # conflict with the RPMs from other buildrequired modules. This is done to prefer modular # RPMs over base module RPMs even if their NVR is lower. if conf.system in ("koji", "test"): handle_collisions_with_base_module_rpms(mmd, arches) else: log.warning( "The necessary conflicts could not be generated due to RHBZ#1693683. " "Some RPMs from the base modules (%s) may end up being used over modular RPMs. " "This may result in different behavior than a production build.", ", ".join(conf.base_module_names)) mmd = record_filtered_rpms(mmd) build.modulemd = mmd_to_str(mmd) build.transition(db_session, conf, models.BUILD_STATES["wait"]) # Catch custom exceptions that we can expose to the user except (UnprocessableEntity, Forbidden, ValidationError, RuntimeError) as e: log.exception(str(e)) error_msg = str(e) failure_reason = "user" except (xmlrpclib.ProtocolError, koji.GenericError) as e: log.exception(str(e)) error_msg = 'Koji communication error: "{0}"'.format(str(e)) failure_reason = "infra" except Exception as e: log.exception(str(e)) error_msg = "An unknown error occurred while validating the modulemd" failure_reason = "user" else: db_session.add(build) db_session.commit() finally: if error_msg: # Rollback changes underway db_session.rollback() build.transition( db_session, conf, models.BUILD_STATES["failed"], state_reason=error_msg, failure_type=failure_reason, ) db_session.commit()