Esempio n. 1
0
    def test_consumer_mark_event_as_failed_on_exception(
            self, global_consumer, handle):
        """
        Tests that Consumer.consume marks the DB Event as failed in case there
        is an error in a handler.
        """
        consumer = self.create_consumer()
        global_consumer.return_value = consumer

        @fail_event_on_handler_exception
        def mocked_handle(cls, msg):
            event = Event.get_or_create(db.session, "msg_id", "msg_id", 0)
            ArtifactBuild.create(db.session, event, "foo", 0)
            db.session.commit()
            cls.set_context(event)
            raise ValueError("Expected exception")

        handle.side_effect = mocked_handle

        msg = self._compose_state_change_msg()
        consumer.consume(msg)

        db_event = Event.get(db.session, "msg_id")
        for build in db_event.builds:
            self.assertEqual(build.state, ArtifactBuildState.FAILED.value)
            self.assertTrue(build.state_reason, "Failed with traceback")
    def test_handle_isnt_allowed_by_internal_policy(self):
        event = BotasErrataShippedEvent("test_msg_id", self.botas_advisory)

        self.handler.handle(event)
        db_event = Event.get(db.session, message_id='test_msg_id')

        self.assertEqual(db_event.state, EventState.SKIPPED.value)
        self.assertTrue(db_event.state_reason.startswith(
            "This image rebuild is not allowed by internal policy."))
    def test_handle_manual_isnt_allowed_by_internal_policy(self):
        event = ManualBundleRebuild("test_msg_id", [], [])

        self.handler.handle(event)
        db_event = Event.get(db.session, message_id='test_msg_id')

        self.assertEqual(db_event.state, EventState.SKIPPED.value)
        self.assertTrue(
            db_event.state_reason.startswith(
                "This image rebuild is not allowed by internal policy."))
    def test_handle_no_digests_error(self):
        event = BotasErrataShippedEvent("test_msg_id", self.botas_advisory)
        self.pyxis().get_digests_by_nvrs.return_value = set()
        self.botas_advisory._builds = {}

        self.handler.handle(event)
        db_event = Event.get(db.session, message_id='test_msg_id')

        self.assertEqual(db_event.state, EventState.SKIPPED.value)
        self.assertTrue(
            db_event.state_reason.startswith("There are no digests for NVRs:"))
    def test_handle_no_digests_error(self):
        event = BotasErrataShippedEvent("test_msg_id", self.botas_advisory)
        self.pyxis().get_manifest_list_digest_by_nvr.return_value = None
        self.botas_advisory._builds = {}

        self.handler.handle(event)
        db_event = Event.get(db.session, message_id='test_msg_id')

        self.assertEqual(db_event.state, EventState.SKIPPED.value)
        self.assertTrue(
            db_event.state_reason.startswith(
                "None of the original images have digest"))
 def test_failed_to_build_images_never_built_before(self):
     """
     This test checks that trying to build an image that was never built before (for that
     branch) will make the build fail.
     """
     self.mock_find_images_to_rebuild.return_value = [self.image_a]
     self.mock_find_images_trees_to_rebuild = self.patcher.patch(
         'find_images_trees_to_rebuild', return_value=[[self.image_a]])
     event = FreshmakerAsyncManualBuildEvent(
         'msg-id-123', 'another-branch', ['image-a-container'])
     handler = RebuildImagesOnAsyncManualBuild()
     handler.handle(event)
     db_event = Event.get(db.session, 'msg-id-123')
     self.assertEqual(EventState.FAILED.value, db_event.state)
    def test_building_single_image(self):
        """
        This tests the successful build of a single image
        """
        self.mock_find_images_to_rebuild.return_value = [self.image_a]
        self.mock_find_images_trees_to_rebuild = self.patcher.patch(
            'find_images_trees_to_rebuild', return_value=[[self.image_a]])
        event = FreshmakerAsyncManualBuildEvent(
            'msg-id-123', 'test_branch', ['image-a-container'])
        handler = RebuildImagesOnAsyncManualBuild()
        handler.handle(event)

        db_event = Event.get(db.session, 'msg-id-123')
        self.assertEqual(EventState.BUILDING.value, db_event.state)
        self.mock_get_image_builds_in_first_batch.assert_called_once_with(db.session)
        self.assertEqual(len(db_event.builds.all()), 1)
        self.mock_start_to_build_images.assert_called_once()
    def test_multiple_nvrs_for_the_same_name(self):
        """
        This test checks that when for one name more nvrs are returned by lightblue, Freshmaker
        will pick the one with higher nvr.
        """
        self.mock_find_images_to_rebuild.return_value = [self.image_a, self.image_c]
        self.mock_find_images_trees_to_rebuild = self.patcher.patch(
            'find_images_trees_to_rebuild', return_value=[[self.image_c]])
        event = FreshmakerAsyncManualBuildEvent(
            'msg-id-123', 'test_branch', ['image-a-container'])
        handler = RebuildImagesOnAsyncManualBuild()
        handler.handle(event)

        db_event = Event.get(db.session, 'msg-id-123')
        self.assertEqual(EventState.BUILDING.value, db_event.state)
        self.mock_get_image_builds_in_first_batch.assert_called_once_with(db.session)
        self.mock_start_to_build_images.assert_called_once()
        self.assertEqual(len(db_event.builds.all()), 1)
        self.assertEqual(db_event.builds.one().original_nvr, 'image-a-container-1.0-3')
    def test_handle_get_bundle_paths(self):
        event = BotasErrataShippedEvent("test_msg_id", self.botas_advisory)
        self.pyxis().get_digests_by_nvrs.return_value = {'nvr1'}
        bundles = [
            {
                "bundle_path": "some_path",
                "bundle_path_digest": "sha256:123123",
                "channel_name": "streams-1.5.x",
                "related_images": [
                    {
                        "image": "registry/amq7/amq-streams-r-operator@sha256:111",
                        "name": "strimzi-cluster-operator",
                        "digest": "sha256:111"
                    },
                ],
                "version": "1.5.3"
            },
            {
                "bundle_path": "some_path_2",
                "channel_name": "streams-1.5.x",
                "related_images": [
                    {
                        "image": "registry/amq7/amq-streams-r-operator@sha256:555",
                        "name": "strimzi-cluster-operator",
                        "digest": "sha256:555"
                    },
                ],
                "version": "1.5.4"
            },
        ]
        self.pyxis().filter_bundles_by_related_image_digests.return_value = bundles
        self.botas_advisory._builds = {}

        self.handler.handle(event)
        db_event = Event.get(db.session, message_id='test_msg_id')

        # should be called only with the first digest, because second one
        # doesn't have 'bundle_path_digest'
        self.pyxis().get_images_by_digests.assert_called_once_with({"sha256:123123"})
        self.assertEqual(db_event.state, EventState.SKIPPED.value)
        self.assertTrue(
            db_event.state_reason.startswith("Skipping the rebuild of"))
    def test_parent_if_image_without_parent(self):
        """
        This tests if we get parent as brew build of single image to rebuild
        when image doesn't have "parent" key
        """
        self.mock_find_images_to_rebuild.return_value = [self.image_f]
        event = FreshmakerAsyncManualBuildEvent(
            'msg-id-123', 'test_branch', ['image-a-container'])
        find_parent_mock = MagicMock()
        find_parent_mock.find_parent_brew_build_nvr_from_child.return_value = 'ubi8-container-8.2-299'
        self.mock_lightblue.return_value = find_parent_mock
        RebuildImagesOnAsyncManualBuild().handle(event)

        db_event = Event.get(db.session, 'msg-id-123')

        # Check if build in DB corresponds to parent of the image
        build = db_event.builds.first().json()
        self.assertEqual(build['build_args'].get('original_parent', 0),
                         'ubi8-container-8.2-299')
        # check if we are calling Lightblue to get proper parent of image
        find_parent_mock.find_parent_brew_build_nvr_from_child.assert_called_once_with(self.image_f)
    def test_building_sibilings(self):
        """
        This test checks that when the users requests to rebuild 2 images that are sibilings
        (or other unrelated images) Freshmaker will rebuild them separately, without the need
        of rebuilding the parent.
        """
        self.mock_find_images_to_rebuild.return_value = [self.image_b, self.image_d]
        self.find_images_trees_to_rebuild = self.patcher.patch(
            'find_images_trees_to_rebuild', return_value=[
                [self.image_b, self.image_a, self.image_0],
                [self.image_d, self.image_a, self.image_0]])
        event = FreshmakerAsyncManualBuildEvent(
            'msg-id-123', 'test_branch', ['image-b-container', 'image-d-container'])
        handler = RebuildImagesOnAsyncManualBuild()
        handler.handle(event)

        db_event = Event.get(db.session, 'msg-id-123')
        self.assertEqual(EventState.BUILDING.value, db_event.state)
        self.mock_get_image_builds_in_first_batch.assert_called_once_with(db.session)
        self.assertEqual(len(db_event.builds.all()), 2)
        self.mock_start_to_build_images.assert_called_once()
    def test_related_images_are_built(self):
        self.mock_find_images_to_rebuild.return_value = [self.image_b, self.image_d, self.image_a]
        self.find_images_trees_to_rebuild = self.patcher.patch(
            'find_images_trees_to_rebuild', return_value=[
                [self.image_a, self.image_0],
                [self.image_b, self.image_a, self.image_0],
                [self.image_d, self.image_a, self.image_0]])
        self.mock_generate_batches = self.patcher.patch('generate_batches', return_value=[
            [self.image_a],
            [self.image_b, self.image_d]
        ])
        event = FreshmakerAsyncManualBuildEvent(
            'msg-id-123', 'test_branch',
            ['image-a-container', 'image-b-container', 'image-d-container'])
        handler = RebuildImagesOnAsyncManualBuild()
        handler.handle(event)

        db_event = Event.get(db.session, 'msg-id-123')
        self.assertEqual(EventState.BUILDING.value, db_event.state)
        self.mock_get_image_builds_in_first_batch.assert_called_once_with(db.session)
        self.assertEqual(len(db_event.builds.all()), 3)
        self.mock_start_to_build_images.assert_called_once()
    def test_parent_if_image_with_parent(self):
        """
        This tests if we get parent of single image to rebuild, when image
        has "parent" key as None OR as some image
        """
        for index, image in enumerate([self.image_0, self.image_a], 1):
            self.mock_find_images_to_rebuild.return_value = [image]
            event_id = f'msg-id-{index}'
            event = FreshmakerAsyncManualBuildEvent(
                event_id, 'test_branch', ['image-a-container'])
            RebuildImagesOnAsyncManualBuild().handle(event)

            db_event = Event.get(db.session, event_id)

            if image['parent'] is not None:
                original_parent = image['parent']['brew']['build']
            else:
                original_parent = None

            # Check if build in DB corresponds to parent of the image
            build = db_event.builds.first().json()
            self.assertEqual(build['build_args'].get('original_parent', 0),
                             original_parent)
    def test_multiple_bundles_to_single_related_image(self, mock_koji,
                                                      get_published):
        event = BotasErrataShippedEvent("test_msg_id", self.botas_advisory)
        self.botas_advisory._builds = {
            "product_name": {
                "builds": [{
                    "foo-1-2.123": {
                        "nvr": "foo-1-2.123"
                    }
                }, {
                    "bar-2-2.134": {
                        "nvr": "bar-2-2.134"
                    }
                }]
            }
        }

        published_nvrs = {"foo-1-2.123": "foo-1-2", "bar-2-2.134": "bar-2-2"}
        get_published.side_effect = lambda x: published_nvrs[x]

        digests_by_nvrs = {
            "foo-1-2": "sha256:111",
            "bar-2-2": "sha256:222",
            "foo-1-2.123": "sha256:333",
            "bar-2-2.134": "sha256:444",
        }

        def gmldbn(nvr, must_be_published=True):
            return digests_by_nvrs[nvr]

        self.pyxis().get_manifest_list_digest_by_nvr.side_effect = gmldbn

        bundles_by_related_digest = {
            "sha256:111": [
                {
                    "bundle_path":
                    "bundle-a/path",
                    "bundle_path_digest":
                    "sha256:123123",
                    "channel_name":
                    "streams-1.5.x",
                    "csv_name":
                    "amq-streams.1.5.3",
                    "related_images": [
                        {
                            "image": "foo@sha256:111",
                            "name": "foo",
                            "digest": "sha256:111"
                        },
                    ],
                    "version":
                    "1.5.3"
                },
                {
                    "bundle_path":
                    "bundle-b/path",
                    "bundle_path_digest":
                    "sha256:023023",
                    "channel_name":
                    "4.5",
                    "csv_name":
                    "amq-streams.2.4.2",
                    "related_images": [
                        {
                            "image": "foo@sha256:111",
                            "name": "foo",
                            "digest": "sha256:111"
                        },
                    ],
                    "version":
                    "2.4.2"
                },
            ],
            "sha256:222": []
        }
        self.pyxis().get_bundles_by_related_image_digest.side_effect = \
            lambda x, _: bundles_by_related_digest[x]

        bundle_images = {
            "sha256:123123": [{
                "brew": {
                    "build": "foo-a-bundle-2.1-2",
                    "nvra": "foo-a-bundle-2.1-2.amd64",
                    "package": "foo-a-bundle",
                },
                "repositories": [{
                    "content_advisory_ids": [],
                    "manifest_list_digest": "sha256:12322",
                    "manifest_schema2_digest": "sha256:123123",
                    "published": True,
                    "registry": "registry.example.com",
                    "repository": "foo/foo-a-operator-bundle",
                    "tags": [{
                        "name": "2"
                    }, {
                        "name": "2.1"
                    }],
                }],
            }],
            "sha256:023023": [{
                "brew": {
                    "build": "foo-b-bundle-3.1-2",
                    "nvra": "foo-b-bundle-3.1-2.amd64",
                    "package": "foo-b-bundle",
                },
                "repositories": [{
                    "content_advisory_ids": [],
                    "manifest_list_digest": "sha256:12345",
                    "manifest_schema2_digest": "sha256:023023",
                    "published": True,
                    "registry": "registry.example.com",
                    "repository": "foo/foo-b-operator-bundle",
                    "tags": [{
                        "name": "3"
                    }, {
                        "name": "3.1"
                    }],
                }],
            }]
        }
        self.pyxis(
        ).get_images_by_digest.side_effect = lambda x: bundle_images[x]

        def _fake_get_auto_rebuild_tags(registry, repository):
            if repository == "foo/foo-a-operator-bundle":
                return ["2", "latest"]
            if repository == "foo/foo-b-operator-bundle":
                return ["3", "latest"]

        self.pyxis(
        ).get_auto_rebuild_tags.side_effect = _fake_get_auto_rebuild_tags

        koji_builds = {
            "foo-a-bundle-2.1-2": {
                "build_id": 123,
                "extra": {
                    "image": {
                        "operator_manifests": {
                            "related_images": {
                                "created_by_osbs":
                                True,
                                "pullspecs": [{
                                    "new":
                                    "registry.example.com/foo/foo-container@sha256:111",
                                    "original":
                                    "registry.exampl.com/foo/foo-container:0.1",
                                    "pinned": True,
                                }],
                            }
                        },
                    }
                },
                "name": "foo-a-bundle",
                "nvr": "foo-a-bundle-2.1-2",
            },
            "foo-b-bundle-3.1-2": {
                "build_id": 234,
                "extra": {
                    "image": {
                        "operator_manifests": {
                            "related_images": {
                                "created_by_osbs":
                                True,
                                "pullspecs": [{
                                    "new":
                                    "registry.example.com/foo/foo-container@sha256:111",
                                    "original":
                                    "registry.exampl.com/foo/foo-container:0.1",
                                    "pinned": True,
                                }],
                            }
                        },
                    }
                },
                "name": "foo-b-bundle",
                "nvr": "foo-b-bundle-3.1-2",
            }
        }
        mock_koji.return_value.get_build.side_effect = lambda x: koji_builds[x]
        self.handler._prepare_builds = MagicMock()
        self.handler.start_to_build_images = MagicMock()

        self.handler.handle(event)
        db_event = Event.get(db.session, message_id='test_msg_id')

        self.pyxis().get_images_by_digest.assert_has_calls(
            [call("sha256:123123"),
             call("sha256:023023")], any_order=True)
        self.assertEqual(db_event.state, EventState.BUILDING.value)