#1092 Init event handler handles module stream collision
Merged 5 years ago by mprahl. Opened 5 years ago by cqi.
cqi/fm-orchestrator fix-stream-collision  into  master

@@ -35,6 +35,7 @@ 

      generate_koji_tag,

      record_filtered_rpms)

  from module_build_service.errors import UnprocessableEntity, Forbidden, ValidationError

+ from module_build_service.utils.ursine import handle_stream_collision_modules

  

  from requests.exceptions import ConnectionError

  
@@ -152,6 +153,7 @@ 

      try:

          mmd = build.mmd()

          record_component_builds(mmd, build, session=session)

+         handle_stream_collision_modules(mmd)

          mmd = record_filtered_rpms(mmd)

          build.modulemd = mmd.dumps()

          build.transition(conf, models.BUILD_STATES["wait"])

@@ -41,8 +41,8 @@ 

  from module_build_service.errors import (

      ValidationError, UnprocessableEntity, Forbidden, Conflict)

  from module_build_service import glib

+ from module_build_service.resolver import GenericResolver

  from .mse import generate_expanded_mmds

- from module_build_service.utils.ursine import record_stream_collision_modules

  

  

  def record_filtered_rpms(mmd):
@@ -53,19 +53,41 @@ 

      * Reads the mmd["xmd"]["buildrequires"] and extends it with "filtered_rpms"

        list containing the NVRs of filtered RPMs in a buildrequired module.

  

-     * Every base module could have stream collision modules, whose built RPMs

-       should be filtered out to avoid collision. The filtered out RPMs will be

-       stored into the base module as well.

- 

      :param Modulemd mmd: Modulemd that will be built next.

      :rtype: Modulemd.Module

      :return: Modulemd extended with the "filtered_rpms" in XMD section.

      """

+     # Imported here to allow import of utils in GenericBuilder.

+     from module_build_service.builder import GenericBuilder

+ 

+     resolver = GenericResolver.create(conf)

+     builder = GenericBuilder.backends[conf.system]

+ 

      new_buildrequires = {}

      for req_name, req_data in mmd.get_xmd()["mbs"]["buildrequires"].items():

-         _record_filtered_rpms(req_name, req_data)

-         if req_name in conf.base_module_names and 'stream_collision_modules' in req_data:

-             _record_ursine_rpms(req_data)

+         # In case this is module resubmit or local build, the filtered_rpms

+         # will already be there, so there is no point in generating them again.

+         if "filtered_rpms" in req_data:

+             continue

+ 

+         # We can just get the first modulemd data from result right here thanks to

+         # strict=True, so in case the module cannot be found, get_module_modulemds

+         # raises an exception.

+         req_mmd = resolver.get_module_modulemds(

+             req_name, req_data["stream"], req_data["version"], req_data["context"], True)[0]

+ 

+         # Find out the particular NVR of filtered packages

+         filtered_rpms = []

+         rpm_filter = req_mmd.get_rpm_filter()

+         if rpm_filter and rpm_filter.get():

+             rpm_filter = rpm_filter.get()

+             built_nvrs = builder.get_built_rpms_in_module_build(req_mmd)

+             for nvr in built_nvrs:

+                 parsed_nvr = kobo.rpmlib.parse_nvr(nvr)

+                 if parsed_nvr["name"] in rpm_filter:

+                     filtered_rpms.append(nvr)

+         req_data["filtered_rpms"] = filtered_rpms

+ 

          new_buildrequires[req_name] = req_data

  

      # Replace the old buildrequires with new ones.
@@ -75,91 +97,6 @@ 

      return mmd

  

  

- def _record_filtered_rpms(req_name, req_data):

-     """Store filtered RPMs by a buildrequire module

- 

-     This methods looks for key ``filtered_rpms`` in a buildrequired module's

-     metadata. If there is, nothing is done, just keep it unchanged, which case

-     could be a module is resubmitted or a local build.

- 

-     Otherwise, ``_record_filtered_rpms`` will get module's RPMs listed in

-     filter section, then store them with the key into metadata in place.

- 

-     :param str req_name: name of a buildrequired module.

-     :param dict req_data: a mapping containing metadata of the buildrequired

-         module. A pair of ``req_name`` and ``req_data`` is usually the one of

-         xmd.mbs.buildrequires, which are stored during the module stream

-         expansion process. At least, ``req_data`` must have keys stream,

-         version and context. Key ``filtered_rpms`` will be added as a list of

-         RPMs N-E:V-R.

-     """

-     # Imported here to allow import of utils in GenericBuilder.

-     from module_build_service.builder import GenericBuilder

- 

-     # In case this is module resubmit or local build, the filtered_rpms

-     # will already be there, so there is no point in generating them again.

-     if "filtered_rpms" in req_data:

-         return

- 

-     resolver = module_build_service.resolver.GenericResolver.create(conf)

- 

-     # We can just get the first modulemd data from result right here thanks to

-     # strict=True, so in case the module cannot be found, get_module_modulemds

-     # raises an exception.

-     req_mmd = resolver.get_module_modulemds(

-         req_name, req_data["stream"], req_data["version"], req_data["context"], True)[0]

- 

-     # Find out the particular NVR of filtered packages

-     filtered_rpms = []

-     rpm_filter = req_mmd.get_rpm_filter()

-     if rpm_filter and rpm_filter.get():

-         rpm_filter = rpm_filter.get()

-         built_nvrs = GenericBuilder.backends[conf.system].get_built_rpms_in_module_build(

-             req_mmd)

-         for nvr in built_nvrs:

-             parsed_nvr = kobo.rpmlib.parse_nvr(nvr)

-             if parsed_nvr["name"] in rpm_filter:

-                 filtered_rpms.append(nvr)

-     req_data["filtered_rpms"] = filtered_rpms

- 

- 

- def _record_ursine_rpms(req_data):

-     """Store ursine RPMs

- 

-     This method handles key ``stream_collision_modules`` from a buildrequired

-     module's metadata to find out all built RPMs and then store them with a new

-     key ``ursine_rpms`` into metadata in place.

- 

-     :param dict req_data: a mapping containing metadata of the buildrequired

-         module. At least, ``req_data`` must have keys stream, version and

-         context. As a result, a new key ``filtered_ursine_rpms`` will be added

-         with a list of RPMs N-E:V-R which are built for the found stream

-         collision modules.

-     """

-     from module_build_service.builder.KojiModuleBuilder import KojiModuleBuilder

-     resolver = module_build_service.resolver.GenericResolver.create(conf)

- 

-     # Key stream_collision_modules is not used after rpms are recorded, but

-     # just keep it here in case it would be helpful in the future.

-     modules_nsvc = req_data['stream_collision_modules']

-     built_rpms = []

- 

-     koji_session = KojiModuleBuilder.get_session(conf, None)

- 

-     for nsvc in modules_nsvc:

-         name, stream, version, context = nsvc.split(':')

-         module = resolver._get_module(name, stream, version, context, strict=True)

-         rpms = koji_session.listTaggedRPMS(module['koji_tag'], latest=True)[0]

-         built_rpms.extend(

-             kobo.rpmlib.make_nvr(rpm, force_epoch=True) for rpm in rpms

-         )

- 

-     # In case there is duplicate NEVRs, ensure every NEVR is unique in the final list.

-     # And, sometimes, sorted list of RPMs would be easier to read.

-     built_rpms = sorted(set(built_rpms))

-     req_data['ursine_rpms'] = built_rpms

- 

- 

  def _scm_get_latest(pkg):

      try:

          # If the modulemd specifies that the 'f25' branch is what
@@ -587,9 +524,6 @@ 

              module.transition(conf, transition_to, "Resubmitted by %s" % username)

              log.info("Resumed existing module build in previous state %s" % module.state)

          else:

-             log.info('Start to handle potential module stream collision.')

-             record_stream_collision_modules(mmd)

- 

              log.debug('Creating new module build')

              module = models.ModuleBuild.create(

                  db.session,

@@ -184,10 +184,11 @@ 

      return collision_modules

  

  

- def record_stream_collision_modules(mmd):

+ def handle_stream_collision_modules(mmd):

      """

      Find out modules from ursine content and record those that are buildrequire

-     module but have different stream.

+     module but have different stream. And finally, record built RPMs of these

+     found modules for later use to exclude them from buildroot.

  

      Note that this depends on the result of module stream expansion.

  
@@ -205,6 +206,7 @@ 

      :param mmd: a module's metadata which will be built.

      :type mmd: Modulemd.Module

      """

+     log.info('Start to find out stream collision modules.')

      unpacked_xmd = glib.from_variant_dict(mmd.get_xmd())

      buildrequires = unpacked_xmd['mbs']['buildrequires']

  
@@ -214,15 +216,65 @@ 

              log.info(

                  'Base module %s is not a buildrequire of module %s. '

                  'Skip handling module stream collision for this base module.',

-                 mmd.get_name())

+                 module_name, mmd.get_name())

+             continue

+ 

+         # Module stream collision is handled only for newly created module

+         # build. However, if a build is resumed and restarted from init

+         # state, we have to ensure stream collision is not handled twice for a

+         # base module.

+         # Just check the existence, and following code ensures this key exists

+         # even if no stream collision module is found.

+         if ('stream_collision_modules' in base_module_info and

+                 'ursine_rpms' in base_module_info):

+             log.debug('Base module %s has stream collision modules and ursine '

+                       'rpms. Skip to handle stream collision again for it.',

+                       module_name)

              continue

  

          modules_nsvc = find_stream_collision_modules(

              buildrequires, base_module_info['koji_tag'])

+ 

          if modules_nsvc:

+             # Save modules NSVC for later use in subsequent event handlers to

+             # log readable messages.

              base_module_info['stream_collision_modules'] = modules_nsvc

+             base_module_info['ursine_rpms'] = find_module_built_rpms(modules_nsvc)

          else:

              log.info('No stream collision module is found against base module %s.',

                       module_name)

+             # Always set in order to mark it as handled already.

+             base_module_info['stream_collision_modules'] = None

+             base_module_info['ursine_rpms'] = None

  

      mmd.set_xmd(glib.dict_values(unpacked_xmd))

+ 

+ 

+ def find_module_built_rpms(modules_nsvc):

Optional: This looks like a good candidate to be a KojiModuleBuilder method.

+     """Find out built RPMs of given modules

+ 

+     :param modules_nsvc: a list of modules' NSVC to find out built RPMs for

+         each of them.

+     :type modules_nsvc: list[str]

+     :return: a sorted list of RPMs, each of them is represented as NEVR.

+     :rtype: list[str]

+     """

+     import kobo.rpmlib

+     from module_build_service.resolver import GenericResolver

+     from module_build_service.builder.KojiModuleBuilder import KojiModuleBuilder

+     resolver = GenericResolver.create(conf)

+ 

+     built_rpms = []

+     koji_session = KojiModuleBuilder.get_session(conf, None)

+ 

+     for nsvc in modules_nsvc:

+         name, stream, version, context = nsvc.split(':')

+         module = resolver._get_module(name, stream, version, context, strict=True)

+         rpms = koji_session.listTaggedRPMS(module['koji_tag'], latest=True)[0]

+         built_rpms.extend(

+             kobo.rpmlib.make_nvr(rpm, force_epoch=True) for rpm in rpms

+         )

+ 

+     # In case there is duplicate NEVRs, ensure every NEVR is unique in the final list.

+     # And, sometimes, sorted list of RPMs would be easier to read.

+     return sorted(set(built_rpms))

@@ -292,7 +292,7 @@ 

      import moksha.hub.reactor # noqa

  

  

- @patch('module_build_service.utils.submit.record_stream_collision_modules')

+ @patch('module_build_service.scheduler.handlers.modules.handle_stream_collision_modules')

  @patch.object(module_build_service.config.Config, 'system', new_callable=PropertyMock,

                return_value='test')

  @patch("module_build_service.builder.GenericBuilder.default_buildroot_groups",
@@ -1259,7 +1259,7 @@ 

              except Exception:

                  pass

  

-     @patch('module_build_service.utils.submit.record_stream_collision_modules')

+     @patch('module_build_service.scheduler.handlers.modules.handle_stream_collision_modules')

      @patch('module_build_service.auth.get_user', return_value=user)

      @patch('module_build_service.scm.SCM')

      @patch("module_build_service.config.Config.mock_resultsdir",

@@ -58,7 +58,8 @@ 

      @patch("module_build_service.builder.KojiModuleBuilder.KojiModuleBuilder."

             "get_built_rpms_in_module_build")

      @patch('module_build_service.scm.SCM')

-     def test_init_basic(self, mocked_scm, built_rpms):

+     @patch('module_build_service.scheduler.handlers.modules.handle_stream_collision_modules')

+     def test_init_basic(self, rscm, mocked_scm, built_rpms):

          FakeSCM(mocked_scm, 'testmodule', 'testmodule_init.yaml',

                  '620ec77321b2ea7b0d67d82992dda3e1d67055b4')

  

file modified
+74 -16
@@ -18,6 +18,8 @@ 

  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE

  # SOFTWARE.

  

+ import copy

+ 

  from mock import patch, Mock

  

  from module_build_service import conf, glib
@@ -208,15 +210,15 @@ 

          original_xmd = glib.from_variant_dict(fake_mmd.get_xmd())

  

          with patch.object(ursine, 'log') as log:

-             ursine.record_stream_collision_modules(fake_mmd)

-             log.info.assert_called_once()

+             ursine.handle_stream_collision_modules(fake_mmd)

+             assert 2 == log.info.call_count

              find_stream_collision_modules.assert_not_called()

  

          assert original_xmd == glib.from_variant_dict(fake_mmd.get_xmd())

  

      @patch.object(conf, 'base_module_names', new=['platform'])

      @patch('module_build_service.utils.ursine.get_modulemds_from_ursine_content')

-     def test_nothing_changed_if_no_modules_in_ursine_content(

+     def test_mark_handled_even_if_no_modules_in_ursine_content(

              self, get_modulemds_from_ursine_content):

          xmd = {

              'mbs': {
@@ -232,14 +234,21 @@ 

          get_modulemds_from_ursine_content.return_value = []

  

          with patch.object(ursine, 'log') as log:

-             ursine.record_stream_collision_modules(fake_mmd)

-             log.info.assert_called()

+             ursine.handle_stream_collision_modules(fake_mmd)

+             assert 2 == log.info.call_count

  

-         assert original_xmd == glib.from_variant_dict(fake_mmd.get_xmd())

+         expected_xmd = copy.deepcopy(original_xmd)

+         # Ensure stream_collision_modules is set.

+         expected_xmd['mbs']['buildrequires']['platform']['stream_collision_modules'] = ''

+         expected_xmd['mbs']['buildrequires']['platform']['ursine_rpms'] = ''

+         assert expected_xmd == glib.from_variant_dict(fake_mmd.get_xmd())

  

      @patch.object(conf, 'base_module_names', new=['platform', 'project-platform'])

      @patch('module_build_service.utils.ursine.get_modulemds_from_ursine_content')

-     def test_add_collision_modules(self, get_modulemds_from_ursine_content):

+     @patch('module_build_service.resolver.GenericResolver.create')

+     @patch('koji.ClientSession')

+     def test_add_collision_modules(self, ClientSession, resolver_create,

+                                    get_modulemds_from_ursine_content):

          xmd = {

              'mbs': {

                  'buildrequires': {
@@ -253,35 +262,84 @@ 

                  }

              }

          }

-         fake_mmd = make_module('name1:s:2020:c', xmd=xmd, store_to_db=False)

+         fake_mmd = make_module('name1:s:2020:c',

+                                xmd=xmd, store_to_db=False)

  

          def mock_get_ursine_modulemds(koji_tag):

              if koji_tag == 'module-rhel-8.0-build':

                  return [

-                     make_module('modulea:10:20180813041838:5ea3b708', store_to_db=False),

-                     make_module('moduleb:1.0:20180113042038:6ea3b105', store_to_db=False),

+                     # This is the one

+                     make_module('modulea:10:20180813041838:5ea3b708',

+                                 store_to_db=False),

+                     make_module('moduleb:1.0:20180113042038:6ea3b105',

+                                 store_to_db=False),

                  ]

              if koji_tag == 'module-project-1.0-build':

                  return [

-                     make_module('bar:6:20181013041838:817fa3a8', store_to_db=False),

-                     make_module('foo:2:20180113041838:95f078a1', store_to_db=False),

+                     # Both of them are the collided modules

+                     make_module('bar:6:20181013041838:817fa3a8',

+                                 store_to_db=False),

+                     make_module('foo:2:20180113041838:95f078a1',

+                                 store_to_db=False),

                  ]

  

          get_modulemds_from_ursine_content.side_effect = mock_get_ursine_modulemds

  

-         ursine.record_stream_collision_modules(fake_mmd)

+         # Mock for finding out built rpms

+         def mock_get_module(name, stream, version, context, strict=True):

+             return {

+                 'modulea:10:20180813041838:5ea3b708': {

+                     'koji_tag': 'module-modulea-10-20180813041838-5ea3b708',

+                 },

+                 'bar:6:20181013041838:817fa3a8': {

+                     'koji_tag': 'module-bar-6-20181013041838-817fa3a8',

+                 },

+                 'foo:2:20180113041838:95f078a1': {

+                     'koji_tag': 'module-foo-2-20180113041838-95f078a1',

+                 },

+             }['{}:{}:{}:{}'.format(name, stream, version, context)]

+ 

+         resolver = resolver_create.return_value

+         resolver._get_module.side_effect = mock_get_module

+ 

+         def mock_listTaggedRPMS(tag, latest):

+             return {

+                 'module-modulea-10-20180813041838-5ea3b708': [[

+                     {'name': 'pkg1', 'version': '1.0', 'release': '1.fc28',

+                      'epoch': None},

+                 ]],

+                 'module-bar-6-20181013041838-817fa3a8': [[

+                     {'name': 'pkg2', 'version': '2.0', 'release': '1.fc28',

+                      'epoch': None},

+                 ]],

+                 'module-foo-2-20180113041838-95f078a1': [[

+                     {'name': 'pkg3', 'version': '3.0', 'release': '1.fc28',

+                      'epoch': None},

+                 ]],

+             }[tag]

+ 

+         koji_session = ClientSession.return_value

+         koji_session.listTaggedRPMS.side_effect = mock_listTaggedRPMS

+ 

+         ursine.handle_stream_collision_modules(fake_mmd)

  

          xmd = glib.from_variant_dict(fake_mmd.get_xmd())

          buildrequires = xmd['mbs']['buildrequires']

  

          assert (['modulea:10:20180813041838:5ea3b708'] ==

                  buildrequires['platform']['stream_collision_modules'])

+         assert (['pkg1-0:1.0-1.fc28'] ==

+                 buildrequires['platform']['ursine_rpms'])

  

-         modules = buildrequires['project-platform']['stream_collision_modules']

-         modules.sort()

-         expected_modules = ['bar:6:20181013041838:817fa3a8', 'foo:2:20180113041838:95f078a1']

+         modules = sorted(

+             buildrequires['project-platform']['stream_collision_modules'])

+         expected_modules = ['bar:6:20181013041838:817fa3a8',

+                             'foo:2:20180113041838:95f078a1']

          assert expected_modules == modules

  

+         assert (['pkg2-0:2.0-1.fc28', 'pkg3-0:3.0-1.fc28'] ==

+                 sorted(buildrequires['project-platform']['ursine_rpms']))

+ 

  

  class TestFindStreamCollisionModules:

      """Test ursine.find_stream_collision_modules"""

@@ -1093,123 +1093,3 @@ 

              assert len(local_modules) == 1

              assert local_modules[0].koji_tag.endswith(

                  "/module-platform-f28-3/results")

- 

- 

- class TestRecordFilteredRPMs:

-     """Test submit.record_filtered_rpms"""

- 

-     def setup_method(self):

-         clean_database(add_platform_module=False)

- 

-         # Prepare fake data for resolver.get_module_modulemds

-         xmd = {

-             'mbs': {

-                 'buildrequires': {

-                     # This module has its own filtered_rpms, which should be unchanged.

-                     'modulea': {'stream': '201808', 'version': '2', 'context': '00000000',

-                                 'filtered_rpms': ['pkg-1.0-1.fc28']},

- 

-                     # Whereas no filtered_rpms in this module, filtered rpms should be

-                     # injected eventually.

-                     'moduleb': {'stream': '7', 'version': '2', 'context': '00000000'},

- 

-                     # For test recording rpms included in stream collision modules

-                     'platform': {'stream': 'f28', 'version': '2', 'context': '00000000',

-                                  # Don't care about platform module's filtered rpms here

-                                  'filtered_rpms': [],

-                                  'stream_collision_modules': ['foo:master:1:00000000',

-                                                               'bar:master:2:00000000']},

-                 }

-             }

-         }

- 

-         self.mmd = make_module('cool-module:201809:1:00000000', xmd=xmd, store_to_db=False)

- 

-         # Store buildrequires modules into database in order to be queried in the test

-         for module_name, md_dict in xmd['mbs']['buildrequires'].items():

-             br_module_nsvc = (module_name, md_dict['stream'],

-                               md_dict['version'], md_dict['context'])

-             br_module_xmd = {

-                 'mbs': {

-                     'koji_tag': 'module-{}-{}-{}-{}'.format(*br_module_nsvc),

-                 }

-             }

-             br_module_filtered_rpms = None

-             if module_name == 'moduleb':

-                 # Add this RPM to filter section.

-                 # Test will verify if this package is listed in final filtered_rpms list.

-                 br_module_filtered_rpms = ['foo']

- 

-             # Modules have to be created in database whose NSVC appears in

-             # stream_collision_modules. This is for testing recording rpms

-             # built for stream collision modules.

-             if module_name == 'platform':

-                 for nsvc in md_dict['stream_collision_modules']:

-                     make_module(nsvc, xmd={'mbs': {

-                         'koji_tag': 'module-{}-{}-{}-{}'.format(*nsvc.split(':'))

-                     }})

- 

-             make_module('{}:{}:{}:{}'.format(*br_module_nsvc),

-                         filtered_rpms=br_module_filtered_rpms,

-                         xmd=br_module_xmd)

- 

-     def teardown_method(self):

-         clean_database()

- 

-     @patch('koji.ClientSession')

-     def test_generate_and_store_filtered_rpms(self, ClientSession):

- 

-         def mocklistTaggedRPMs(tag, latest):

-             # Result returned from listTaggedRPMs should contain two lists.

-             # The second one is the build, which is not used in test and

-             # omitted here.

-             rpms = {

-                 'module-modulea-201808-2-00000000': [

-                     [

-                         {'name': 'pkg1', 'version': '1.0', 'release': '1.fc28'},

-                         {'name': 'pkg2', 'version': '2.34', 'release': '1.fc28'},

-                     ],

-                 ],

-                 'module-moduleb-7-2-00000000': [

-                     [

-                         {'name': 'foo', 'version': '2.0', 'release': '1.fc28'},

-                         {'name': 'bar', 'version': '1.0', 'release': '1.fc28'},

-                     ],

-                 ],

- 

-                 # These rpms are built for stream collision modules. See above

-                 # in setup_method.

-                 'module-foo-master-1-00000000': [

-                     [

-                         {'name': 'foo-a', 'version': '1.0', 'release': '1.fc28'},

-                         {'name': 'foo-a-devel', 'version': '1.0', 'release': '1.fc28'},

-                     ],

-                 ],

-                 'module-bar-master-2-00000000': [

-                     [

-                         {'name': 'bar-a', 'version': '0.2', 'release': '2.fc28'},

-                         {'name': 'bar-a-devel', 'version': '0.2', 'release': '2.fc28'},

-                     ],

-                 ]

-             }

-             return rpms[tag]

- 

-         ClientSession.return_value.listTaggedRPMS.side_effect = mocklistTaggedRPMs

- 

-         with patch.object(conf, 'resolver', new='db'):

-             mmd = module_build_service.utils.submit.record_filtered_rpms(self.mmd)

- 

-         xmd_mbs = mmd.get_xmd()['mbs'].unpack()

- 

-         assert ['pkg-1.0-1.fc28'] == xmd_mbs['buildrequires']['modulea']['filtered_rpms']

-         assert ['foo-0:2.0-1.fc28'] == xmd_mbs['buildrequires']['moduleb']['filtered_rpms']

- 

-         expected_ursine_rpms = [

-             'foo-a-0:1.0-1.fc28', 'foo-a-devel-0:1.0-1.fc28',

-             'bar-a-0:0.2-2.fc28', 'bar-a-devel-0:0.2-2.fc28',

-         ]

-         expected_ursine_rpms.sort()

- 

-         found_ursine_rpms = xmd_mbs['buildrequires']['platform']['ursine_rpms']

-         found_ursine_rpms.sort()

-         assert expected_ursine_rpms == found_ursine_rpms

@@ -756,10 +756,9 @@ 

          assert data['meta']['total'] == 0

  

      @pytest.mark.parametrize('api_version', [1, 2])

-     @patch('module_build_service.utils.submit.record_stream_collision_modules')

      @patch('module_build_service.auth.get_user', return_value=user)

      @patch('module_build_service.scm.SCM')

-     def test_submit_build(self, mocked_scm, mocked_get_user, rscm, api_version):

+     def test_submit_build(self, mocked_scm, mocked_get_user, api_version):

          FakeSCM(mocked_scm, 'testmodule', 'testmodule.yaml',

                  '620ec77321b2ea7b0d67d82992dda3e1d67055b4')

  
@@ -805,10 +804,9 @@ 

          assert module.buildrequires[0].context == '00000000'

          assert module.buildrequires[0].stream_version == 280000

  

-     @patch('module_build_service.utils.submit.record_stream_collision_modules')

      @patch('module_build_service.auth.get_user', return_value=user)

      @patch('module_build_service.scm.SCM')

-     def test_submit_build_no_base_module(self, mocked_scm, mocked_get_user, rscm):

+     def test_submit_build_no_base_module(self, mocked_scm, mocked_get_user):

          FakeSCM(mocked_scm, 'testmodule', 'testmodule-no-base-module.yaml',

                  '620ec77321b2ea7b0d67d82992dda3e1d67055b4')

  
@@ -823,12 +821,11 @@ 

              'error': 'Unprocessable Entity'

          }

  

-     @patch('module_build_service.utils.submit.record_stream_collision_modules')

      @patch('module_build_service.auth.get_user', return_value=user)

      @patch('module_build_service.scm.SCM')

      @patch('module_build_service.config.Config.rebuild_strategy_allow_override',

             new_callable=PropertyMock, return_value=True)

-     def test_submit_build_rebuild_strategy(self, mocked_rmao, mocked_scm, mocked_get_user, hmsc):

+     def test_submit_build_rebuild_strategy(self, mocked_rmao, mocked_scm, mocked_get_user):

          FakeSCM(mocked_scm, 'testmodule', 'testmodule.yaml',

                  '620ec77321b2ea7b0d67d82992dda3e1d67055b4')

  
@@ -902,10 +899,9 @@ 

          }

          assert data == expected_error

  

-     @patch('module_build_service.utils.submit.record_stream_collision_modules')

      @patch('module_build_service.auth.get_user', return_value=user)

      @patch('module_build_service.scm.SCM')

-     def test_submit_componentless_build(self, mocked_scm, mocked_get_user, rscm):

+     def test_submit_componentless_build(self, mocked_scm, mocked_get_user):

          FakeSCM(mocked_scm, 'fakemodule', 'fakemodule.yaml',

                  '3da541559918a808c2402bba5012f6c60b27661c')

  
@@ -1127,12 +1123,11 @@ 

          assert result['status'] == 400

          assert "The request contains 'owner' parameter" in result['message']

  

-     @patch('module_build_service.utils.submit.record_stream_collision_modules')

      @patch('module_build_service.auth.get_user', return_value=anonymous_user)

      @patch('module_build_service.scm.SCM')

      @patch("module_build_service.config.Config.no_auth", new_callable=PropertyMock,

             return_value=True)

-     def test_submit_build_no_auth_set_owner(self, mocked_conf, mocked_scm, mocked_get_user, hmsc):

+     def test_submit_build_no_auth_set_owner(self, mocked_conf, mocked_scm, mocked_get_user):

          FakeSCM(mocked_scm, 'testmodule', 'testmodule.yaml',

                  '620ec77321b2ea7b0d67d82992dda3e1d67055b4')

  
@@ -1148,11 +1143,10 @@ 

          build = ModuleBuild.query.filter(ModuleBuild.id == result['id']).one()

          assert (build.owner == result['owner'] == 'foo') is True

  

-     @patch('module_build_service.utils.submit.record_stream_collision_modules')

      @patch('module_build_service.auth.get_user', return_value=anonymous_user)

      @patch('module_build_service.scm.SCM')

      @patch("module_build_service.config.Config.no_auth", new_callable=PropertyMock)

-     def test_patch_set_different_owner(self, mocked_no_auth, mocked_scm, mocked_get_user, hmsc):

+     def test_patch_set_different_owner(self, mocked_no_auth, mocked_scm, mocked_get_user):

          FakeSCM(mocked_scm, 'testmodule', 'testmodule.yaml',

                  '620ec77321b2ea7b0d67d82992dda3e1d67055b4')

  
@@ -1193,11 +1187,10 @@ 

          assert data['status'] == 422

          assert data['error'] == 'Unprocessable Entity'

  

-     @patch('module_build_service.utils.submit.record_stream_collision_modules')

      @patch('module_build_service.auth.get_user', return_value=user)

      @patch('module_build_service.scm.SCM')

      @patch("module_build_service.config.Config.allow_custom_scmurls", new_callable=PropertyMock)

-     def test_submit_custom_scmurl(self, allow_custom_scmurls, mocked_scm, mocked_get_user, hmsc):

+     def test_submit_custom_scmurl(self, allow_custom_scmurls, mocked_scm, mocked_get_user):

          FakeSCM(mocked_scm, 'testmodule', 'testmodule.yaml',

                  '620ec77321b2ea7b0d67d82992dda3e1d67055b4')

  
@@ -1220,11 +1213,10 @@ 

          (['f28'], None),

          (['f28'], ['f28']),

      ))

-     @patch('module_build_service.utils.submit.record_stream_collision_modules')

      @patch('module_build_service.auth.get_user', return_value=user)

      @patch('module_build_service.scm.SCM')

      def test_submit_build_dep_override(

-             self, mocked_scm, mocked_get_user, rscm, br_override_streams, req_override_streams):

+             self, mocked_scm, mocked_get_user, br_override_streams, req_override_streams):

          init_data(data_size=1, multiple_stream_versions=True)

          FakeSCM(mocked_scm, 'testmodule', 'testmodule_platform_f290000.yaml',

                  '620ec77321b2ea7b0d67d82992dda3e1d67055b4')