def test_check_manifest_dir_exists(self, tmp_path, dry_run):
     with pytest.raises(
             ValueError,
             match=r'/manifests is not a directory or does not exist'):
         replace_image_references(str(tmp_path / 'manifests'),
                                  io.StringIO(),
                                  dry_run=dry_run)
    def test_skip_replacements(self, tmp_path, dry_run):
        eggs_image_reference = 'registry.example.com/eggs:9.8'
        spam_image_reference = 'registry.example.com/maps/spam-operator:1.2'

        eggs_image_reference_resolved = 'registry.example.com/eggs@sha256:2'
        spam_image_reference_resolved = 'registry.example.com/maps/spam-operator@sha256:1'

        manifest_dir = tmp_path / 'manifests'
        manifest_dir.mkdir()
        csv_path = manifest_dir / 'spam.yaml'
        original_csv_text = CSV_TEMPLATE_WITH_RELATED_IMAGES.format(
            eggs=eggs_image_reference, spam=spam_image_reference)
        csv_path.write_text(original_csv_text)

        replacements = {
            spam_image_reference: spam_image_reference_resolved,
            eggs_image_reference: eggs_image_reference_resolved,
        }
        replacements_input_file = io.StringIO()
        json.dump(replacements, replacements_input_file)
        replacements_input_file.seek(0)

        replace_image_references(str(manifest_dir),
                                 replacements_input_file,
                                 dry_run=dry_run)

        # relatedImages section exists, CSV should not be modified
        assert csv_path.read_text() == original_csv_text
    def test_partial_replacement(self, tmp_path, dry_run):
        eggs_image_reference = 'registry.example.com/eggs:9.8'
        spam_image_reference = 'registry.example.com/maps/spam-operator:1.2'

        eggs_image_reference_resolved = 'registry.example.com/eggs@sha256:2'

        manifest_dir = tmp_path / 'manifests'
        manifest_dir.mkdir()
        csv_path = manifest_dir / 'spam.yaml'
        original_csv_text = CSV_TEMPLATE.format(eggs=eggs_image_reference,
                                                spam=spam_image_reference)
        csv_path.write_text(original_csv_text)

        replacements = {
            eggs_image_reference: eggs_image_reference_resolved,
        }
        replacements_input_file = io.StringIO()
        json.dump(replacements, replacements_input_file)
        replacements_input_file.seek(0)

        replace_image_references(str(manifest_dir),
                                 replacements_input_file,
                                 dry_run=dry_run)

        if dry_run:
            assert csv_path.read_text() == original_csv_text
        else:
            # spam image reference is not resolved
            assert csv_path.read_text() == CSV_RESOLVED_TEMPLATE.format(
                eggs=eggs_image_reference_resolved, spam=spam_image_reference)
    def test_error_on_related_images_with_related_image_env(
            self, tmp_path, dry_run):
        eggs_image_reference = 'registry.example.com/eggs:9.8'
        spam_image_reference = 'registry.example.com/maps/spam-operator:1.2'

        manifest_dir = tmp_path / 'manifests'
        manifest_dir.mkdir()
        csv_path = manifest_dir / 'spam.yaml'
        # relatedImages is set and one of the containers uses an environment variable
        # with the suffix RELATED_IMAGE_. This is not allowed.
        original_csv_text = dedent("""\
            apiVersion: operators.coreos.com/v1alpha1
            kind: ClusterServiceVersion
            metadata:
              name: foo
            spec:
              install:
                spec:
                  deployments:
                  - spec:
                      template:
                        spec:
                          containers:
                          - name: spam-operator
                            image: {spam}
                            env:
                            - name: RELATED_IMAGE_BACON
                              value: {eggs}
              relatedImages:
              - name: spam-operator
                image: {spam}
              - name: eggs
                image: {eggs}
        """).format(spam=spam_image_reference, eggs=eggs_image_reference)
        csv_path.write_text(original_csv_text)

        replacements_input_file = io.StringIO()
        json.dump({}, replacements_input_file)
        replacements_input_file.seek(0)

        with pytest.raises(ValueError, match=r'This is not allowed'):
            replace_image_references(str(manifest_dir),
                                     replacements_input_file,
                                     dry_run=dry_run)

        # Verify CSV is left intact after failure
        assert csv_path.read_text() == original_csv_text