Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true

module Packages
  module Debian
    class ProcessPackageFileService
      include ExclusiveLeaseGuard
      include Gitlab::Utils::StrongMemoize

      SOURCE_FIELD_SPLIT_REGEX = /[ ()]/
      # used by ExclusiveLeaseGuard
      DEFAULT_LEASE_TIMEOUT = 1.hour.to_i.freeze

      SIMPLE_DEB_FILE_TYPES = %i[deb udeb ddeb].freeze

      def initialize(package_file, distribution_name, component_name)
        @package_file = package_file
        @distribution_name = distribution_name
        @component_name = component_name
      end

      def execute
        return if @package_file.package.pending_destruction?

        validate!

        try_obtain_lease do
          distribution.transaction do
            rename_package_and_set_version
            update_package
            update_files_metadata if changes_file?
            update_file_metadata
            cleanup_temp_package
          end

          ::Packages::Debian::GenerateDistributionWorker.perform_async(:project, package.debian_distribution.id)
        end
      end

      private

      def validate!
        raise ArgumentError, 'package file without Debian metadata' unless @package_file.debian_file_metadatum
        raise ArgumentError, 'already processed package file' unless @package_file.debian_file_metadatum.unknown?

        changes_file? ? validate_changes_file! : validate_package_file!
      end

      def changes_file?
        @package_file.file_name.end_with?('.changes')
      end

      def validate_changes_file!
        raise ArgumentError, 'unwanted distribution name' unless @distribution_name.nil?
        raise ArgumentError, 'unwanted component name' unless @component_name.nil?
        raise ArgumentError, 'missing Source field' unless file_metadata.dig(:fields, 'Source').present?
        raise ArgumentError, 'missing Version field' unless file_metadata.dig(:fields, 'Version').present?
        raise ArgumentError, 'missing Distribution field' unless file_metadata.dig(:fields, 'Distribution').present?
      end

      def validate_package_file!
        raise ArgumentError, 'missing distribution name' unless @distribution_name.present?
        raise ArgumentError, 'missing component name' unless @component_name.present?

        return if SIMPLE_DEB_FILE_TYPES.include?(file_metadata[:file_type])

        raise ArgumentError, "invalid package file type: #{file_metadata[:file_type]}"
      end

      def file_metadata
        metadata_service_class.new(@package_file).execute
      end
      strong_memoize_attr :file_metadata

      def metadata_service_class
        changes_file? ? ::Packages::Debian::ExtractChangesMetadataService : ::Packages::Debian::ExtractMetadataService
      end

      def distribution
        Packages::Debian::DistributionsFinder.new(
          @package_file.package.project,
          codename_or_suite: package_distribution
        ).execute.last!
      end
      strong_memoize_attr :distribution

      def package_distribution
        return file_metadata[:fields]['Distribution'] if changes_file?

        @distribution_name
      end

      def package
        packages = temp_package.project
                               .packages
                               .existing_debian_packages_with(name: package_name, version: package_version)
        package = packages.with_debian_codename_or_suite(package_distribution)
                          .first

        unless package
          package_in_other_distribution = packages.first

          if package_in_other_distribution
            raise ArgumentError, "Debian package #{package_name} #{package_version} exists " \
                                 "in distribution #{package_in_other_distribution.debian_distribution.codename}"
          end
        end

        package || temp_package
      end
      strong_memoize_attr :package

      def temp_package
        @package_file.package
      end
      strong_memoize_attr :temp_package

      def package_name
        return file_metadata[:fields]['Source'] if changes_file?

        package_name_and_version[0]
      end

      def package_version
        return file_metadata[:fields]['Version'] if changes_file?

        package_name_and_version[1]
      end

      def package_name_and_version
        package_name = file_metadata[:fields]['Package']
        package_version = file_metadata[:fields]['Version']

        if file_metadata[:fields]['Source']
          # "sample" or "sample (1.2.3~alpha2)"
          source_field_parts = file_metadata[:fields]['Source'].split(SOURCE_FIELD_SPLIT_REGEX)
          package_name = source_field_parts[0]
          package_version = source_field_parts[2] || package_version
        end

        [package_name, package_version]
      end
      strong_memoize_attr :package_name_and_version

      def rename_package_and_set_version
        package.update!(
          name: package_name,
          version: package_version,
          status: :default
        )
      end

      def update_package
        return unless using_temporary_package?

        package.update!(
          debian_publication_attributes: { distribution_id: distribution.id }
        )
      end

      def using_temporary_package?
        package.id == temp_package.id
      end

      def update_files_metadata
        file_metadata[:files].each do |_, entry|
          file_metadata = ::Packages::Debian::ExtractMetadataService.new(entry.package_file).execute

          ::Packages::UpdatePackageFileService.new(entry.package_file, package_id: package.id)
            .execute

          # Force reload from database, as package has changed
          entry.package_file.reload_package

          entry.package_file.debian_file_metadatum.update!(
            file_type: file_metadata[:file_type],
            component: entry.component,
            architecture: file_metadata[:architecture],
            fields: file_metadata[:fields]
          )
        end
      end

      def update_file_metadata
        ::Packages::UpdatePackageFileService.new(@package_file, package_id: package.id)
          .execute

        # Force reload from database, as package has changed
        @package_file.reload_package

        @package_file.debian_file_metadatum.update!(
          file_type: file_metadata[:file_type],
          component: @component_name,
          architecture: file_metadata[:architecture],
          fields: file_metadata[:fields]
        )
      end

      def cleanup_temp_package
        temp_package.destroy unless using_temporary_package?
      end

      # used by ExclusiveLeaseGuard
      def lease_key
        "packages:debian:process_package_file_service:#{temp_package.project_id}_#{package_name}_#{package_version}"
      end

      # used by ExclusiveLeaseGuard
      def lease_timeout
        DEFAULT_LEASE_TIMEOUT
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Packages::Debian::ProcessPackageFileService, feature_category: :package_registry do
  include ExclusiveLeaseHelpers

  let_it_be(:distribution) { create(:debian_project_distribution, :with_file, suite: 'unstable') }

  let(:debian_file_metadatum) { package_file.debian_file_metadatum }
  let(:service) { described_class.new(package_file, distribution_name, component_name) }

  describe '#execute' do
    using RSpec::Parameterized::TableSyntax

    subject { service.execute }

    shared_examples 'common validations' do
      context 'with package file without Debian metadata' do
        let!(:package_file) { create(:debian_package_file, without_loaded_metadatum: true) }

        let(:expected_error) { ArgumentError }
        let(:expected_message) { 'package file without Debian metadata' }

        it_behaves_like 'raises error'
      end

      context 'with already processed package file' do
        let!(:package_file) { create(:debian_package_file) }

        let(:expected_error) { ArgumentError }
        let(:expected_message) { 'already processed package file' }

        it_behaves_like 'raises error'
      end

      context 'without a distribution' do
        let(:expected_error) { ActiveRecord::RecordNotFound }
        let(:expected_message) { /^Couldn't find Packages::Debian::ProjectDistribution with / }

        before do
          # Workaround ActiveRecord cache
          Packages::Debian::ProjectDistribution.find(distribution.id).delete
        end

        it_behaves_like 'raises error'
      end

      context 'when there is a matching published package in another distribution' do
        let!(:matching_package) do
          create(
            :debian_package,
            project: distribution.project,
            name: 'sample',
            version: '1.2.3~alpha2'
          )
        end

        let(:expected_error) { ArgumentError }

        let(:expected_message) do
          "Debian package sample 1.2.3~alpha2 exists in distribution #{matching_package.debian_distribution.codename}"
        end

        it_behaves_like 'raises error'
      end
    end

    shared_examples 'raises error' do
      it 'raises error', :aggregate_failures do
        expect(::Packages::Debian::GenerateDistributionWorker).not_to receive(:perform_async)
        expect { subject }
          .to not_change(Packages::Package, :count)
          .and not_change(Packages::PackageFile, :count)
          .and not_change { Packages::Debian::Publication.count }
          .and not_change(package.package_files, :count)
          .and not_change { package.reload.name }
          .and not_change { package.version }
          .and not_change { package.status }
          .and not_change { debian_file_metadatum&.reload&.file_type }
          .and not_change { debian_file_metadatum&.component }
          .and raise_error(expected_error, expected_message)
      end
    end

    shared_examples 'does nothing' do
      it 'does nothing', :aggregate_failures do
        expect(::Packages::Debian::GenerateDistributionWorker).not_to receive(:perform_async)
        expect { subject }
          .to not_change(Packages::Package, :count)
          .and not_change(Packages::PackageFile, :count)
          .and not_change { Packages::Debian::Publication.count }
          .and not_change(package.package_files, :count)
          .and not_change { package.reload.name }
          .and not_change { package.version }
          .and not_change { package.status }
          .and not_change { debian_file_metadatum&.reload&.file_type }
          .and not_change { debian_file_metadatum&.component }
      end
    end

    shared_examples 'updates package and changes file' do
      it 'updates package and changes file', :aggregate_failures do
        expect(::Packages::Debian::GenerateDistributionWorker)
          .to receive(:perform_async).with(:project, distribution.id)
        expect { subject }
          .to not_change(Packages::Package, :count)
          .and not_change(Packages::PackageFile, :count)
          .and change { Packages::Debian::Publication.count }.by(1)
          .and change { package.package_files.count }.from(1).to(8)
          .and change { package.reload.name }.to('sample')
          .and change { package.version }.to('1.2.3~alpha2')
          .and change { package.status }.from('processing').to('default')
          .and change { package.debian_publication }.from(nil)
          .and change { debian_file_metadatum.file_type }.from('unknown').to('changes')
          .and not_change { debian_file_metadatum.component }
      end
    end

    shared_examples 'updates package and package file' do
      it 'updates package and package file', :aggregate_failures do
        expect(::Packages::Debian::GenerateDistributionWorker)
          .to receive(:perform_async).with(:project, distribution.id)
        expect { subject }
          .to not_change(Packages::Package, :count)
          .and not_change(Packages::PackageFile, :count)
          .and change { Packages::Debian::Publication.count }.by(1)
          .and not_change(package.package_files, :count)
          .and change { package.reload.name }.to('sample')
          .and change { package.version }.to('1.2.3~alpha2')
          .and change { package.status }.from('processing').to('default')
          .and change { package.debian_publication }.from(nil)
          .and change { debian_file_metadatum.file_type }.from('unknown').to(expected_file_type)
          .and change { debian_file_metadatum.component }.from(nil).to(component_name)
      end
    end

    context 'with a changes file' do
      let!(:incoming) { create(:debian_incoming, project: distribution.project) }
      let!(:temporary_with_changes) { create(:debian_temporary_with_changes, project: distribution.project) }
      let(:package) { temporary_with_changes }

      let(:package_file) { temporary_with_changes.package_files.first }
      let(:distribution_name) { nil }
      let(:component_name) { nil }

      it_behaves_like 'common validations'

      context 'with distribution_name' do
        let(:distribution_name) { distribution.codename }
        let(:expected_error) { ArgumentError }
        let(:expected_message) { 'unwanted distribution name' }

        it_behaves_like 'raises error'
      end

      context 'with component_name' do
        let(:component_name) { 'main' }
        let(:expected_error) { ArgumentError }
        let(:expected_message) { 'unwanted component name' }

        it_behaves_like 'raises error'
      end

      context 'with crafted file_metadata' do
        let(:complete_file_metadata) do
          {
            file_type: :changes,
            fields: {
              'Source' => 'abc',
              'Version' => '1.0',
              'Distribution' => 'sid'
            }
          }
        end

        let(:expected_error) { ArgumentError }

        before do
          allow_next_instance_of(::Packages::Debian::ExtractChangesMetadataService) do |extract_changes_metadata_svc|
            allow(extract_changes_metadata_svc).to receive(:execute).and_return(file_metadata)
          end
        end

        context 'with missing Source field' do
          let(:file_metadata) { complete_file_metadata.tap { |m| m[:fields].delete 'Source' } }
          let(:expected_message) { 'missing Source field' }

          it_behaves_like 'raises error'
        end

        context 'with missing Version field' do
          let(:file_metadata) { complete_file_metadata.tap { |m| m[:fields].delete 'Version' } }
          let(:expected_message) { 'missing Version field' }

          it_behaves_like 'raises error'
        end

        context 'with missing Distribution field' do
          let(:file_metadata) { complete_file_metadata.tap { |m| m[:fields].delete 'Distribution' } }
          let(:expected_message) { 'missing Distribution field' }

          it_behaves_like 'raises error'
        end
      end

      context 'when lease is already taken' do
        before do
          stub_exclusive_lease_taken(
            "packages:debian:process_package_file_service:#{distribution.project_id}_sample_1.2.3~alpha2",
            timeout: Packages::Debian::ProcessPackageFileService::DEFAULT_LEASE_TIMEOUT)
        end

        it_behaves_like 'does nothing'
      end

      context 'when there is no matching published package' do
        it_behaves_like 'updates package and changes file'
      end

      context 'when there is a matching published package' do
        let!(:matching_package) do
          create(
            :debian_package,
            project: distribution.project,
            published_in: distribution,
            name: 'sample',
            version: '1.2.3~alpha2'
          )
        end

        it 'reuses existing package and update package file', :aggregate_failures do
          expect(::Packages::Debian::GenerateDistributionWorker)
            .to receive(:perform_async).with(:project, distribution.id)
          expect { subject }
            .to change { Packages::Package.count }.from(3).to(2)
            .and not_change { Packages::PackageFile.count }
            .and not_change(Packages::Debian::Publication, :count)
            .and change { package.package_files.count }.from(1).to(0)
            .and change { incoming.package_files.count }.from(7).to(0)
            .and change { matching_package.package_files.count }.from(7).to(15)
            .and change { package_file.package }.from(package).to(matching_package)
            .and not_change(matching_package, :name)
            .and not_change(matching_package, :version)
            .and change { debian_file_metadatum.file_type }.from('unknown').to('changes')
            .and not_change { debian_file_metadatum.component }

          expect { package.reload }
            .to raise_error(ActiveRecord::RecordNotFound)
        end
      end

      context 'when there is a matching published package pending destruction' do
        let!(:matching_package) do
          create(
            :debian_package,
            :pending_destruction,
            project: distribution.project,
            published_in: distribution,
            name: 'sample',
            version: '1.2.3~alpha2'
          )
        end

        it_behaves_like 'updates package and changes file'
      end
    end

    context 'with a package file' do
      let!(:temporary_with_files) { create(:debian_temporary_with_files, project: distribution.project) }
      let(:package) { temporary_with_files }

      let(:package_file) { package.package_files.with_file_name('libsample0_1.2.3~alpha2_amd64.deb').first }
      let(:distribution_name) { distribution.codename }
      let(:component_name) { 'main' }

      where(:case_name, :expected_file_type, :file_name, :component_name) do
        'with a deb'   | 'deb'  | 'libsample0_1.2.3~alpha2_amd64.deb'   | 'main'
        'with an udeb' | 'udeb' | 'sample-udeb_1.2.3~alpha2_amd64.udeb' | 'contrib'
        'with an ddeb' | 'ddeb' | 'sample-ddeb_1.2.3~alpha2_amd64.ddeb' | 'main'
      end

      with_them do
        context 'with Debian package file' do
          let(:package_file) { package.package_files.with_file_name(file_name).first }

          it_behaves_like 'common validations'

          context 'without distribution name' do
            let(:distribution_name) { '' }
            let(:expected_error) { ArgumentError }
            let(:expected_message) { 'missing distribution name' }

            it_behaves_like 'raises error'
          end

          context 'without component name' do
            let(:component_name) { '' }
            let(:expected_error) { ArgumentError }
            let(:expected_message) { 'missing component name' }

            it_behaves_like 'raises error'
          end

          context 'with invalid package file type' do
            let(:package_file) { package.package_files.with_file_name('sample_1.2.3~alpha2.tar.xz').first }
            let(:expected_error) { ArgumentError }
            let(:expected_message) { 'invalid package file type: source' }

            it_behaves_like 'raises error'
          end

          context 'when lease is already taken' do
            before do
              stub_exclusive_lease_taken(
                "packages:debian:process_package_file_service:#{distribution.project_id}_sample_1.2.3~alpha2",
                timeout: Packages::Debian::ProcessPackageFileService::DEFAULT_LEASE_TIMEOUT)
            end

            it_behaves_like 'does nothing'
          end

          context 'when there is no matching published package' do
            it_behaves_like 'updates package and package file'

            context 'with suite as distribution name' do
              let(:distribution_name) { distribution.suite }

              it_behaves_like 'updates package and package file'
            end
          end

          context 'when there is a matching published package' do
            let!(:matching_package) do
              create(
                :debian_package,
                project: distribution.project,
                published_in: distribution,
                name: 'sample',
                version: '1.2.3~alpha2'
              )
            end

            it 'reuses existing package and update package file', :aggregate_failures do
              expect(::Packages::Debian::GenerateDistributionWorker)
                .to receive(:perform_async).with(:project, distribution.id)
              expect { subject }
                .to change { Packages::Package.count }.from(2).to(1)
                .and change { Packages::PackageFile.count }.from(14).to(8)
                .and not_change(Packages::Debian::Publication, :count)
                .and change { package.package_files.count }.from(7).to(0)
                .and change { package_file.package }.from(package).to(matching_package)
                .and not_change(matching_package, :name)
                .and not_change(matching_package, :version)
                .and change { debian_file_metadatum.file_type }.from('unknown').to(expected_file_type)
                .and change { debian_file_metadatum.component }.from(nil).to(component_name)

              expect { package.reload }
                .to raise_error(ActiveRecord::RecordNotFound)
            end
          end

          context 'when there is a matching published package pending destruction' do
            let!(:matching_package) do
              create(
                :debian_package,
                :pending_destruction,
                project: distribution.project,
                published_in: distribution,
                name: 'sample',
                version: '1.2.3~alpha2'
              )
            end

            it_behaves_like 'updates package and package file'
          end
        end
      end
    end
  end

  describe '#lease_key' do
    let(:prefix) { 'packages:debian:process_package_file_service' }

    subject { service.send(:lease_key) }

    context 'with a changes file' do
      let!(:incoming) { create(:debian_incoming, project: distribution.project) }
      let!(:temporary_with_changes) { create(:debian_temporary_with_changes, project: distribution.project) }
      let(:package) { temporary_with_changes }

      let(:package_file) { temporary_with_changes.package_files.first }
      let(:distribution_name) { nil }
      let(:component_name) { nil }

      it { is_expected.to eq("#{prefix}:#{distribution.project_id}_sample_1.2.3~alpha2") }
    end

    context 'with a package file' do
      let!(:temporary_with_files) { create(:debian_temporary_with_files, project: distribution.project) }
      let(:package) { temporary_with_files }

      let(:package_file) { package.package_files.with_file_name('libsample0_1.2.3~alpha2_amd64.deb').first }
      let(:distribution_name) { distribution.codename }
      let(:component_name) { 'main' }

      it { is_expected.to eq("#{prefix}:#{distribution.project_id}_sample_1.2.3~alpha2") }
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true
module Packages
  module Maven
    class CreatePackageService < ::Packages::CreatePackageService
      def execute
        app_group, _, app_name = params[:name].rpartition('/')
        app_group.tr!('/', '.')

        create_package!(:maven,
          maven_metadatum_attributes: {
            path: params[:path],
            app_group: app_group,
            app_name: app_name,
            app_version: params[:version]
          }
        )
      end
    end
  end
end

```

Response:
# frozen_string_literal: true
require 'spec_helper'

RSpec.describe Packages::Maven::CreatePackageService, feature_category: :package_registry do
  let(:project) { create(:project) }
  let(:user) { create(:user) }
  let(:app_name) { 'my-app' }
  let(:version) { '1.0-SNAPSHOT' }
  let(:path) { "my/company/app/#{app_name}" }
  let(:path_with_version) { "#{path}/#{version}" }

  describe '#execute' do
    subject(:package) { described_class.new(project, user, params).execute }

    context 'with version' do
      let(:params) do
        {
          path: path_with_version,
          name: path,
          version: version
        }
      end

      it 'creates a new package with metadatum' do
        expect(package).to be_valid
        expect(package.name).to eq(path)
        expect(package.version).to eq(version)
        expect(package.package_type).to eq('maven')
        expect(package.maven_metadatum).to be_valid
        expect(package.maven_metadatum.path).to eq(path_with_version)
        expect(package.maven_metadatum.app_group).to eq('my.company.app')
        expect(package.maven_metadatum.app_name).to eq(app_name)
        expect(package.maven_metadatum.app_version).to eq(version)
      end

      it_behaves_like 'assigns the package creator'
    end

    context 'without version' do
      let(:params) do
        {
          path: path,
          name: path,
          version: nil
        }
      end

      it 'creates a new package with metadatum' do
        package = described_class.new(project, user, params).execute

        expect(package).to be_valid
        expect(package.name).to eq(path)
        expect(package.version).to be nil
        expect(package.maven_metadatum).to be_valid
        expect(package.maven_metadatum.path).to eq(path)
        expect(package.maven_metadatum.app_group).to eq('my.company.app')
        expect(package.maven_metadatum.app_name).to eq(app_name)
        expect(package.maven_metadatum.app_version).to be nil
      end

      it_behaves_like 'assigns the package creator'
    end

    context 'path is missing' do
      let(:params) do
        {
          name: path,
          version: version
        }
      end

      it 'raises an error' do
        service = described_class.new(project, user, params)

        expect { service.execute }.to raise_error(ActiveRecord::RecordInvalid)
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true
module Packages
  module Maven
    class FindOrCreatePackageService < BaseService
      SNAPSHOT_TERM = '-SNAPSHOT'
      MAX_FILE_NAME_LENGTH = 5000

      def execute
        return ServiceResponse.error(message: 'File name is too long') if file_name_too_long?

        package =
          ::Packages::Maven::PackageFinder.new(current_user, project, path: path)
          .execute&.last

        unless Namespace::PackageSetting.duplicates_allowed?(package)
          return ServiceResponse.error(message: 'Duplicate package is not allowed') if target_package_is_duplicate?(package)
        end

        unless package
          # Maven uploads several files during `mvn deploy` in next order:
          #   - my-company/my-app/1.0-SNAPSHOT/my-app.jar
          #   - my-company/my-app/1.0-SNAPSHOT/my-app.pom
          #   - my-company/my-app/1.0-SNAPSHOT/maven-metadata.xml
          #   - my-company/my-app/maven-metadata.xml
          #
          # The last xml file does not have VERSION in URL because it contains
          # information about all versions. When uploading such file, we create
          # a package with a version set to `nil`. The xml file with a version
          # is only created and uploaded for snapshot versions.
          #
          # Gradle has a different upload order:
          #   - my-company/my-app/1.0-SNAPSHOT/maven-metadata.xml
          #   - my-company/my-app/1.0-SNAPSHOT/my-app.jar
          #   - my-company/my-app/1.0-SNAPSHOT/my-app.pom
          #   - my-company/my-app/maven-metadata.xml
          #
          # The first upload has to create the proper package (the one with the version set).
          if file_name == Packages::Maven::Metadata.filename && !snapshot_version?
            package_name = path
            version = nil
          else
            package_name, _, version = path.rpartition('/')
          end

          package_params = {
            name: package_name,
            path: path,
            status: params[:status],
            version: version
          }

          package =
            ::Packages::Maven::CreatePackageService.new(project, current_user, package_params)
                                                   .execute
        end

        package.create_build_infos!(params[:build])

        ServiceResponse.success(payload: { package: package })
      end

      private

      def file_name_too_long?
        return false unless file_name

        file_name.size > MAX_FILE_NAME_LENGTH
      end

      def target_package_is_duplicate?(package)
        # duplicate metadata files can be uploaded multiple times
        return false if package.version.nil?

        existing_file_names = strip_snapshot_parts(
          package.package_files
                 .map(&:file_name)
                 .compact
        )

        published_file_name = strip_snapshot_parts_from(file_name)
        existing_file_names.include?(published_file_name)
      end

      def strip_snapshot_parts(file_names)
        return file_names unless snapshot_version?

        Array.wrap(file_names).map { |f| strip_snapshot_parts_from(f) }
      end

      def strip_snapshot_parts_from(file_name)
        return file_name unless snapshot_version?
        return unless file_name

        match_data = file_name.match(Gitlab::Regex::Packages::MAVEN_SNAPSHOT_DYNAMIC_PARTS)

        if match_data
          file_name.gsub(match_data.captures.last, "")
        else
          file_name
        end
      end

      def snapshot_version?
        path&.ends_with?(SNAPSHOT_TERM)
      end

      def path
        params[:path]
      end

      def file_name
        params[:file_name]
      end
    end
  end
end

```

Response:
# frozen_string_literal: true
require 'spec_helper'

RSpec.describe Packages::Maven::FindOrCreatePackageService, feature_category: :package_registry do
  let_it_be(:project) { create(:project) }
  let_it_be(:user) { create(:user) }

  let(:app_name) { 'my-app' }
  let(:path) { "sandbox/test/app/#{app_name}" }
  let(:version) { '1.0.0' }
  let(:file_name) { 'test.jar' }
  let(:param_path) { "#{path}/#{version}" }
  let(:params) { { path: param_path, file_name: file_name } }
  let(:service) { described_class.new(project, user, params) }

  describe '#execute' do
    using RSpec::Parameterized::TableSyntax

    subject { service.execute }

    shared_examples 'reuse existing package' do
      it { expect { subject }.not_to change { Packages::Package.count } }

      it 'returns the existing package' do
        expect(subject.payload).to eq(package: existing_package)
      end
    end

    shared_examples 'create package' do
      it { expect { subject }.to change { Packages::Package.count }.by(1) }

      it 'sets the proper name and version', :aggregate_failures do
        pkg = subject.payload[:package]

        expect(pkg.name).to eq(path)
        expect(pkg.version).to eq(version)
      end

      context 'with optional attributes' do
        subject { service.execute.payload[:package] }

        it_behaves_like 'assigns build to package'
        it_behaves_like 'assigns status to package'
      end
    end

    shared_examples 'returning an error' do |with_message: ''|
      it { expect { subject }.not_to change { project.package_files.count } }

      it 'returns an error', :aggregate_failures do
        expect(subject.payload).to be_empty
        expect(subject.errors).to include(with_message)
      end
    end

    context 'path with version' do
      # Note that "path with version" and "file type maven metadata xml" only exists for snapshot versions
      # In other words, we will never have an metadata xml upload on a path with version for a non snapshot version
      where(:package_exist, :file_type, :snapshot_version, :shared_example_name) do
        true  | :jar       | false | 'reuse existing package'
        false | :jar       | false | 'create package'
        true  | :jar       | true  | 'reuse existing package'
        false | :jar       | true  | 'create package'
        true  | :maven_xml | true  | 'reuse existing package'
        false | :maven_xml | true  | 'create package'
      end

      with_them do
        let(:version) { snapshot_version ? '1.0-SNAPSHOT' : '1.0.0' }
        let(:file_name) { file_type == :maven_xml ? 'maven-metadata.xml' : 'test.jar' }

        let!(:existing_package) do
          if package_exist
            create(:maven_package, name: path, version: version, project: project)
          end
        end

        it_behaves_like params[:shared_example_name]
      end
    end

    context 'path without version' do
      let(:param_path) { path }
      let(:version) { nil }

      context 'maven-metadata.xml file' do
        let(:file_name) { 'maven-metadata.xml' }

        context 'with existing package' do
          let!(:existing_package) { create(:maven_package, name: path, version: version, project: project) }

          it_behaves_like 'reuse existing package'

          context 'marked as pending_destruction' do
            before do
              existing_package.pending_destruction!
            end

            it_behaves_like 'create package'
          end
        end

        context 'without existing package' do
          it_behaves_like 'create package'
        end
      end
    end

    context 'with a build' do
      let_it_be(:pipeline) { create(:ci_pipeline, user: user) }

      let(:build) { double('build', pipeline: pipeline) }
      let(:params) { { path: param_path, file_name: file_name, build: build } }

      it 'creates a build_info' do
        expect { subject }.to change { Packages::BuildInfo.count }.by(1)
      end

      context 'with multiple files for the same package and the same pipeline' do
        let(:file_2_params) { params.merge(file_name: 'test2.jar') }
        let(:file_3_params) { params.merge(file_name: 'test3.jar') }

        it 'creates a single build info' do
          expect do
            described_class.new(project, user, params).execute
            described_class.new(project, user, file_2_params).execute
            described_class.new(project, user, file_3_params).execute
          end.to change { ::Packages::BuildInfo.count }.by(1)
        end
      end
    end

    context 'when package duplicates are not allowed' do
      let_it_be_with_refind(:package_settings) { create(:namespace_package_setting, :group, maven_duplicates_allowed: false) }
      let_it_be_with_refind(:group) { package_settings.namespace }
      let_it_be_with_refind(:project) { create(:project, group: group) }

      let!(:existing_package) { create(:maven_package, name: path, version: version, project: project) }

      let(:existing_file_name) { file_name }
      let(:jar_file) { existing_package.package_files.with_file_name_like('%.jar').first }

      before do
        jar_file.update_column(:file_name, existing_file_name)
      end

      it_behaves_like 'returning an error', with_message: 'Duplicate package is not allowed'

      context 'for a SNAPSHOT version' do
        let(:version) { '1.0.0-SNAPSHOT' }

        it_behaves_like 'returning an error', with_message: 'Duplicate package is not allowed'
      end

      context 'when uploading to the versionless package which contains metadata about all versions' do
        let(:version) { nil }
        let(:param_path) { path }

        it_behaves_like 'reuse existing package'
      end

      context 'when uploading different non-duplicate files to the same package' do
        before do
          jar_file.destroy!
        end

        it_behaves_like 'reuse existing package'
      end

      context 'when the package name matches the exception regex' do
        before do
          package_settings.update!(maven_duplicate_exception_regex: existing_package.name)
        end

        it_behaves_like 'reuse existing package'
      end

      context 'when the package version matches the exception regex' do
        before do
          package_settings.update!(maven_duplicate_exception_regex: existing_package.version)
        end

        it_behaves_like 'reuse existing package'
      end

      context 'when uploading a similar package file name with a classifier' do
        let(:existing_file_name) { 'test.jar' }
        let(:file_name) { 'test-javadoc.jar' }

        it_behaves_like 'reuse existing package'

        context 'for a SNAPSHOT version' do
          let(:version) { '1.0.0-SNAPSHOT' }
          let(:existing_file_name) { 'test-1.0-20230303.163304-1.jar' }
          let(:file_name) { 'test-1.0-20230303.163304-1-javadoc.jar' }

          it_behaves_like 'reuse existing package'
        end
      end
    end

    context 'with a very large file name' do
      let(:params) { super().merge(file_name: 'a' * (described_class::MAX_FILE_NAME_LENGTH + 1)) }

      it_behaves_like 'returning an error', with_message: 'File name is too long'
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true

module Packages
  module Maven
    module Metadata
      class AppendPackageFileService
        XML_CONTENT_TYPE = 'application/xml'
        DEFAULT_CONTENT_TYPE = 'application/octet-stream'

        MD5_FILE_NAME = "#{Metadata.filename}.md5"
        SHA1_FILE_NAME = "#{Metadata.filename}.sha1"
        SHA256_FILE_NAME = "#{Metadata.filename}.sha256"
        SHA512_FILE_NAME = "#{Metadata.filename}.sha512"

        def initialize(package:, metadata_content:)
          @package = package
          @metadata_content = metadata_content
        end

        def execute
          return ServiceResponse.error(message: 'package is not set') unless @package
          return ServiceResponse.error(message: 'metadata content is not set') unless @metadata_content

          file_md5 = digest_from(@metadata_content, :md5)
          file_sha1 = digest_from(@metadata_content, :sha1)
          file_sha256 = digest_from(@metadata_content, :sha256)
          file_sha512 = digest_from(@metadata_content, :sha512)

          @package.transaction do
            append_metadata_file(
              content: @metadata_content,
              file_name: Metadata.filename,
              content_type: XML_CONTENT_TYPE,
              sha1: file_sha1,
              md5: file_md5,
              sha256: file_sha256
            )

            append_metadata_file(content: file_md5, file_name: MD5_FILE_NAME) unless Gitlab::FIPS.enabled?
            append_metadata_file(content: file_sha1, file_name: SHA1_FILE_NAME)
            append_metadata_file(content: file_sha256, file_name: SHA256_FILE_NAME)
            append_metadata_file(content: file_sha512, file_name: SHA512_FILE_NAME)
          end

          ServiceResponse.success(message: 'New metadata package file created')
        end

        private

        def append_metadata_file(content:, file_name:, content_type: DEFAULT_CONTENT_TYPE, sha1: nil, md5: nil, sha256: nil)
          file_md5 = md5 || digest_from(content, :md5)
          file_sha1 = sha1 || digest_from(content, :sha1)
          file_sha256 = sha256 || digest_from(content, :sha256)

          file = CarrierWaveStringFile.new_file(
            file_content: content,
            filename: file_name,
            content_type: content_type
          )

          ::Packages::CreatePackageFileService.new(
            @package,
            file: file,
            size: file.size,
            file_name: file_name,
            file_sha1: file_sha1,
            file_md5: file_md5,
            file_sha256: file_sha256
          ).execute
        end

        def digest_from(content, type)
          return if type == :md5 && Gitlab::FIPS.enabled?

          digest_class = case type
                         when :md5
                           Digest::MD5
                         when :sha1
                           Digest::SHA1
                         when :sha256
                           Digest::SHA256
                         when :sha512
                           Digest::SHA512
                         end
          digest_class.hexdigest(content)
        end
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe ::Packages::Maven::Metadata::AppendPackageFileService, feature_category: :package_registry do
  let_it_be(:package) { create(:maven_package, version: nil) }

  let(:service) { described_class.new(package: package, metadata_content: content) }
  let(:content) { 'test' }

  describe '#execute' do
    subject { service.execute }

    context 'with some content' do
      it 'creates all the related package files', :aggregate_failures do
        expect { subject }.to change { package.package_files.count }.by(5)
        expect(subject).to be_success

        expect_file(metadata_file_name, with_content: content, with_content_type: 'application/xml')
        expect_file("#{metadata_file_name}.md5")
        expect_file("#{metadata_file_name}.sha1")
        expect_file("#{metadata_file_name}.sha256")
        expect_file("#{metadata_file_name}.sha512")
      end

      context 'with FIPS mode', :fips_mode do
        it 'does not generate file_md5' do
          expect { subject }.to change { package.package_files.count }.by(4)
          expect(subject).to be_success

          expect_file(metadata_file_name, with_content: content, with_content_type: 'application/xml', fips: true)
          expect_file("#{metadata_file_name}.sha1", fips: true)
          expect_file("#{metadata_file_name}.sha256", fips: true)
          expect_file("#{metadata_file_name}.sha512", fips: true)
        end
      end
    end

    context 'with nil content' do
      let(:content) { nil }

      it_behaves_like 'returning an error service response', message: 'metadata content is not set'
    end

    context 'with nil package' do
      let(:package) { nil }

      it_behaves_like 'returning an error service response', message: 'package is not set'
    end

    def expect_file(file_name, fips: false, with_content: nil, with_content_type: '')
      package_file = package.package_files.recent.with_file_name(file_name).first

      expect(package_file.file).to be_present
      expect(package_file.file_name).to eq(file_name)
      expect(package_file.size).to be > 0
      expect(package_file.file_sha1).to be_present
      expect(package_file.file_sha256).to be_present
      expect(package_file.file.content_type).to eq(with_content_type)

      if fips
        expect(package_file.file_md5).not_to be_present
      else
        expect(package_file.file_md5).to be_present
      end

      if with_content
        expect(package_file.file.read).to eq(with_content)
      end
    end

    def metadata_file_name
      ::Packages::Maven::Metadata.filename
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true

module Packages
  module Maven
    module Metadata
      class CreatePluginsXmlService < BaseCreateXmlService
        XPATH_PLUGIN_ARTIFACT_ID = '//plugin/artifactId'
        XPATH_PLUGINS = '//metadata/plugins'
        EMPTY_PLUGINS_PAYLOAD = {
          changes_exist: true,
          empty_plugins: true
        }.freeze

        def execute
          return ServiceResponse.error(message: 'package not set') unless @package
          return ServiceResponse.error(message: 'metadata_content not set') unless @metadata_content
          return ServiceResponse.error(message: 'metadata_content is invalid') unless plugins_xml_node.present?
          return ServiceResponse.success(payload: EMPTY_PLUGINS_PAYLOAD) if plugin_artifact_ids_from_database.empty?

          changes_exist = update_plugins_list

          payload = { changes_exist: changes_exist, empty_versions: false }
          payload[:metadata_content] = xml_doc.to_xml(indent: INDENT_SPACE) if changes_exist

          ServiceResponse.success(payload: payload)
        end

        private

        def update_plugins_list
          return false if plugin_artifact_ids_from_xml == plugin_artifact_ids_from_database

          plugins_xml_node.children.remove

          plugin_artifact_ids_from_database.each do |artifact_id|
            plugins_xml_node.add_child(plugin_node_for(artifact_id))
          end

          true
        end

        def plugins_xml_node
          xml_doc.xpath(XPATH_PLUGINS)
                   .first
        end
        strong_memoize_attr :plugins_xml_node

        def plugin_artifact_ids_from_xml
          plugins_xml_node.xpath(XPATH_PLUGIN_ARTIFACT_ID)
                            .map(&:content)
        end
        strong_memoize_attr :plugin_artifact_ids_from_xml

        def plugin_artifact_ids_from_database
          package_names = plugin_artifact_ids_from_xml.map do |artifact_id|
            "#{@package.name}/#{artifact_id}"
          end

          packages = @package.project.packages
                                     .maven
                                     .displayable
                                     .with_name(package_names)
                                     .has_version

          ::Packages::Maven::Metadatum.for_package_ids(packages.select(:id))
                                      .order_created
                                      .pluck_app_name
                                      .uniq
        end
        strong_memoize_attr :plugin_artifact_ids_from_database

        def plugin_node_for(artifact_id)
          xml_doc.create_element('plugin').tap do |plugin_node|
            plugin_node.add_child(xml_node('name', artifact_id))
            plugin_node.add_child(xml_node('prefix', prefix_from(artifact_id)))
            plugin_node.add_child(xml_node('artifactId', artifact_id))
          end
        end

        # Maven plugin prefix generation from
        # https://github.com/apache/maven/blob/c3dba0e5ba71ee7cbd62620f669a8c206e71b5e2/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/PluginDescriptor.java#L189
        def prefix_from(artifact_id)
          artifact_id.gsub(/-?maven-?/, '')
                     .gsub(/-?plugin-?/, '')
        end
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe ::Packages::Maven::Metadata::CreatePluginsXmlService, feature_category: :package_registry do
  let_it_be(:group_id) { 'my/test' }
  let_it_be(:package) { create(:maven_package, name: group_id, version: nil) }

  let(:plugins_in_database) { %w[one-maven-plugin two three-maven-plugin] }
  let(:plugins_in_xml) { %w[one-maven-plugin two three-maven-plugin] }
  let(:service) { described_class.new(metadata_content: metadata_xml, package: package) }

  describe '#execute' do
    subject { service.execute }

    before do
      next unless package

      plugins_in_database.each do |plugin|
        create(
          :maven_package,
          name: "#{group_id}/#{plugin}",
          version: '1.0.0',
          project: package.project,
          maven_metadatum_attributes: {
            app_group: group_id.tr('/', '.'),
            app_name: plugin,
            app_version: '1.0.0'
          }
        )
      end
    end

    shared_examples 'returning an xml with plugins from the database' do
      it 'returns an metadata versions xml with versions in the database', :aggregate_failures do
        expect(subject).to be_success
        expect(subject.payload[:changes_exist]).to eq(true)
        expect(subject.payload[:empty_versions]).to eq(false)
        expect(plugins_from(subject.payload[:metadata_content])).to match_array(plugins_in_database)
      end
    end

    shared_examples 'returning no changes' do
      it 'returns no changes', :aggregate_failures do
        expect(subject).to be_success
        expect(subject.payload).to eq(changes_exist: false, empty_versions: false)
      end
    end

    context 'with same plugins on both sides' do
      it_behaves_like 'returning no changes'
    end

    context 'with more plugins' do
      let(:additional_plugins) { %w[four-maven-plugin five] }

      context 'in database' do
        let(:plugins_in_database) { plugins_in_xml + additional_plugins }

        # we can't distinguish that the additional plugin are actually maven plugins
        it_behaves_like 'returning no changes'
      end

      context 'in xml' do
        let(:plugins_in_xml) { plugins_in_database + additional_plugins }

        it_behaves_like 'returning an xml with plugins from the database'
      end
    end

    context 'with no versions in the database' do
      let(:plugins_in_database) { [] }

      it 'returns a success', :aggregate_failures do
        result = subject

        expect(result).to be_success
        expect(result.payload).to eq(changes_exist: true, empty_plugins: true)
      end
    end

    context 'with an incomplete metadata content' do
      let(:metadata_xml) { '<metadata></metadata>' }

      it_behaves_like 'returning an error service response', message: 'metadata_content is invalid'
    end

    context 'with an invalid metadata content' do
      let(:metadata_xml) { '<meta></metadata>' }

      it_behaves_like 'returning an error service response', message: 'metadata_content is invalid'
    end

    it_behaves_like 'handling metadata content pointing to a file for the create xml service'

    it_behaves_like 'handling invalid parameters for create xml service'
  end

  def metadata_xml
    Nokogiri::XML::Builder.new do |xml|
      xml.metadata do
        xml.plugins do
          plugins_in_xml.each do |plugin|
            xml.plugin do
              xml.name(plugin)
              xml.prefix(prefix_from(plugin))
              xml.artifactId(plugin)
            end
          end
        end
      end
    end.to_xml
  end

  def prefix_from(artifact_id)
    artifact_id.gsub(/-?maven-?/, '')
               .gsub(/-?plugin-?/, '')
  end

  def plugins_from(xml_content)
    doc = Nokogiri::XML(xml_content)
    doc.xpath('//metadata/plugins/plugin/artifactId').map(&:content)
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true

module Packages
  module Maven
    module Metadata
      class SyncService < BaseContainerService
        include Gitlab::Utils::StrongMemoize

        alias_method :project, :container

        MAX_FILE_SIZE = 10.megabytes.freeze

        def execute
          return error('Blank package name') unless package_name
          return error('Not allowed') unless Ability.allowed?(current_user, :destroy_package, project)

          result = success('Non existing versionless package(s). Nothing to do.')

          # update versionless package for plugins if it exists
          if metadata_package_file_for_plugins
            result = update_plugins_xml

            return result if result.error?
          end

          # update versionless_package for versions if it exists
          return update_versions_xml if metadata_package_file_for_versions

          result
        end

        private

        def update_versions_xml
          update_xml(
            kind: :versions,
            package_file: metadata_package_file_for_versions,
            service_class: CreateVersionsXmlService,
            payload_empty_field: :empty_versions
          )
        end

        def update_plugins_xml
          update_xml(
            kind: :plugins,
            package_file: metadata_package_file_for_plugins,
            service_class: CreatePluginsXmlService,
            payload_empty_field: :empty_plugins
          )
        end

        def update_xml(kind:, package_file:, service_class:, payload_empty_field:)
          return error("Metadata file for #{kind} is too big") if package_file.size > MAX_FILE_SIZE

          package_file.file.use_open_file do |file|
            result = service_class.new(metadata_content: file, package: package_file.package)
                                  .execute

            next result unless result.success?
            next success("No changes for #{kind} xml") unless result.payload[:changes_exist]

            if result.payload[payload_empty_field]
              package_file.package.destroy!
              success("Versionless package for #{kind} destroyed")
            else
              AppendPackageFileService.new(metadata_content: result.payload[:metadata_content], package: package_file.package)
                                      .execute
            end
          end
        end

        def metadata_package_file_for_versions
          metadata_package_file_for(versionless_package_for_versions)
        end
        strong_memoize_attr :metadata_package_file_for_versions

        def versionless_package_for_versions
          versionless_package_named(package_name)
        end
        strong_memoize_attr :versionless_package_for_versions

        def metadata_package_file_for_plugins
          pkg_name = package_name_for_plugins
          return unless pkg_name

          metadata_package_file_for(versionless_package_named(package_name_for_plugins))
        end
        strong_memoize_attr :metadata_package_file_for_plugins

        def metadata_package_file_for(package)
          return unless package

          package_files = package.installable_package_files

          package_files.with_file_name(Metadata.filename)
                       .recent
                       .first
        end

        def versionless_package_named(name)
          project.packages
                 .maven
                 .displayable
                 .with_name(name)
                 .with_version(nil)
                 .first
        end

        def package_name
          params[:package_name]
        end

        def package_name_for_plugins
          return unless versionless_package_for_versions

          group = versionless_package_for_versions.maven_metadatum.app_group
          group.tr('.', '/')
        end

        def error(message)
          ServiceResponse.error(message: message)
        end

        def success(message)
          ServiceResponse.success(message: message)
        end
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe ::Packages::Maven::Metadata::SyncService, feature_category: :package_registry do
  using RSpec::Parameterized::TableSyntax

  let_it_be(:project) { create(:project) }
  let_it_be(:user) { create(:user) }
  let_it_be_with_reload(:versionless_package_for_versions) { create(:maven_package, name: 'test', version: nil, project: project) }
  let_it_be_with_reload(:metadata_file_for_versions) { create(:package_file, :xml, package: versionless_package_for_versions) }
  let_it_be(:package_file_pending_destruction) { create(:package_file, :pending_destruction, package: versionless_package_for_versions, file_name: Packages::Maven::Metadata.filename) }

  let(:service) { described_class.new(container: project, current_user: user, params: { package_name: versionless_package_for_versions.name }) }

  describe '#execute' do
    let(:create_versions_xml_service_double) { double(::Packages::Maven::Metadata::CreateVersionsXmlService, execute: create_versions_xml_service_response) }
    let(:append_package_file_service_double) { double(::Packages::Maven::Metadata::AppendPackageFileService, execute: append_package_file_service_response) }

    let(:create_versions_xml_service_response) { ServiceResponse.success(payload: { changes_exist: true, empty_versions: false, metadata_content: 'test' }) }
    let(:append_package_file_service_response) { ServiceResponse.success(message: 'New metadata package files created') }

    subject { service.execute }

    before do
      allow(::Packages::Maven::Metadata::CreateVersionsXmlService)
        .to receive(:new).with(metadata_content: an_instance_of(ObjectStorage::Concern::OpenFile), package: versionless_package_for_versions).and_return(create_versions_xml_service_double)
      allow(::Packages::Maven::Metadata::AppendPackageFileService)
        .to receive(:new).with(metadata_content: an_instance_of(String), package: versionless_package_for_versions).and_return(append_package_file_service_double)
    end

    context 'permissions' do
      where(:role, :expected_result) do
        :anonymous  | :rejected
        :developer  | :rejected
        :maintainer | :accepted
      end

      with_them do
        if params[:role] == :anonymous
          let_it_be(:user) { nil }
        end

        before do
          project.send("add_#{role}", user) unless role == :anonymous
        end

        if params[:expected_result] == :rejected
          it_behaves_like 'returning an error service response', message: 'Not allowed'
        else
          it_behaves_like 'returning a success service response', message: 'New metadata package files created'
        end
      end
    end

    context 'with a maintainer' do
      before do
        project.add_maintainer(user)
      end

      context 'with a jar package' do
        before do
          expect(::Packages::Maven::Metadata::CreatePluginsXmlService).not_to receive(:new)
        end

        context 'with no changes' do
          let(:create_versions_xml_service_response) { ServiceResponse.success(payload: { changes_exist: false }) }

          before do
            expect(::Packages::Maven::Metadata::AppendPackageFileService).not_to receive(:new)
          end

          it_behaves_like 'returning a success service response', message: 'No changes for versions xml'
        end

        context 'with changes' do
          let(:create_versions_xml_service_response) { ServiceResponse.success(payload: { changes_exist: true, empty_versions: false, metadata_content: 'new metadata' }) }

          it_behaves_like 'returning a success service response', message: 'New metadata package files created'

          context 'with empty versions' do
            let(:create_versions_xml_service_response) { ServiceResponse.success(payload: { changes_exist: true, empty_versions: true }) }

            before do
              expect(service.send(:versionless_package_for_versions)).to receive(:destroy!)
              expect(::Packages::Maven::Metadata::AppendPackageFileService).not_to receive(:new)
            end

            it_behaves_like 'returning a success service response', message: 'Versionless package for versions destroyed'
          end
        end

        context 'with a too big maven metadata file for versions' do
          before do
            metadata_file_for_versions.update!(size: 100.megabytes)
          end

          it_behaves_like 'returning an error service response', message: 'Metadata file for versions is too big'
        end

        context 'an error from the create versions xml service' do
          let(:create_versions_xml_service_response) { ServiceResponse.error(message: 'metadata_content is invalid') }

          before do
            expect(::Packages::Maven::Metadata::AppendPackageFileService).not_to receive(:new)
          end

          it_behaves_like 'returning an error service response', message: 'metadata_content is invalid'
        end

        context 'an error from the append package file service' do
          let(:append_package_file_service_response) { ServiceResponse.error(message: 'metadata content is not set') }

          it_behaves_like 'returning an error service response', message: 'metadata content is not set'
        end

        context 'without a package name' do
          let(:service) { described_class.new(container: project, current_user: user, params: { package_name: nil }) }

          before do
            expect(::Packages::Maven::Metadata::AppendPackageFileService).not_to receive(:new)
            expect(::Packages::Maven::Metadata::CreateVersionsXmlService).not_to receive(:new)
          end

          it_behaves_like 'returning an error service response', message: 'Blank package name'
        end

        context 'without a versionless package for version' do
          before do
            versionless_package_for_versions.update!(version: '2.2.2')
            expect(::Packages::Maven::Metadata::AppendPackageFileService).not_to receive(:new)
            expect(::Packages::Maven::Metadata::CreateVersionsXmlService).not_to receive(:new)
          end

          it_behaves_like 'returning a success service response', message: 'Non existing versionless package(s). Nothing to do.'
        end

        context 'without a metadata package file for versions' do
          before do
            versionless_package_for_versions.package_files.update_all(file_name: 'test.txt')
            expect(::Packages::Maven::Metadata::AppendPackageFileService).not_to receive(:new)
            expect(::Packages::Maven::Metadata::CreateVersionsXmlService).not_to receive(:new)
          end

          it_behaves_like 'returning a success service response', message: 'Non existing versionless package(s). Nothing to do.'
        end

        context 'without a project' do
          let(:service) { described_class.new(container: nil, current_user: user, params: { package_name: versionless_package_for_versions.name }) }

          before do
            expect(::Packages::Maven::Metadata::AppendPackageFileService).not_to receive(:new)
            expect(::Packages::Maven::Metadata::CreateVersionsXmlService).not_to receive(:new)
          end

          it_behaves_like 'returning an error service response', message: 'Not allowed'
        end
      end

      context 'with a maven plugin package' do
        let_it_be(:versionless_package_name_for_plugins) { versionless_package_for_versions.maven_metadatum.app_group.tr('.', '/') }
        let_it_be_with_reload(:versionless_package_for_plugins) { create(:maven_package, name: versionless_package_name_for_plugins, version: nil, project: project) }
        let_it_be_with_reload(:metadata_file_for_plugins) { create(:package_file, :xml, package: versionless_package_for_plugins) }

        let(:create_plugins_xml_service_double) { double(::Packages::Maven::Metadata::CreatePluginsXmlService, execute: create_plugins_xml_service_response) }
        let(:create_plugins_xml_service_response) { ServiceResponse.success(payload: { changes_exist: false }) }

        before do
          allow(::Packages::Maven::Metadata::CreatePluginsXmlService)
            .to receive(:new).with(metadata_content: an_instance_of(ObjectStorage::Concern::OpenFile), package: versionless_package_for_plugins).and_return(create_plugins_xml_service_double)
          allow(::Packages::Maven::Metadata::AppendPackageFileService)
            .to receive(:new).with(metadata_content: an_instance_of(String), package: versionless_package_for_plugins).and_return(append_package_file_service_double)
        end

        context 'with no changes' do
          let(:create_versions_xml_service_response) { ServiceResponse.success(payload: { changes_exist: false }) }

          before do
            expect(::Packages::Maven::Metadata::AppendPackageFileService).not_to receive(:new)
          end

          it_behaves_like 'returning a success service response', message: 'No changes for versions xml'
        end

        context 'with changes in the versions xml' do
          let(:create_versions_xml_service_response) { ServiceResponse.success(payload: { changes_exist: true, empty_versions: false, metadata_content: 'new metadata' }) }

          it_behaves_like 'returning a success service response', message: 'New metadata package files created'

          context 'with changes in the plugin xml' do
            let(:create_plugins_xml_service_response) { ServiceResponse.success(payload: { changes_exist: true, empty_plugins: false, metadata_content: 'new metadata' }) }

            it_behaves_like 'returning a success service response', message: 'New metadata package files created'
          end

          context 'with empty versions' do
            let(:create_versions_xml_service_response) { ServiceResponse.success(payload: { changes_exist: true, empty_versions: true }) }
            let(:create_plugins_xml_service_response) { ServiceResponse.success(payload: { changes_exist: true, empty_plugins: true }) }

            before do
              expect(service.send(:versionless_package_for_versions)).to receive(:destroy!)
              expect(service.send(:metadata_package_file_for_plugins).package).to receive(:destroy!)
              expect(::Packages::Maven::Metadata::AppendPackageFileService).not_to receive(:new)
            end

            it_behaves_like 'returning a success service response', message: 'Versionless package for versions destroyed'
          end

          context 'with a too big maven metadata file for plugins' do
            before do
              metadata_file_for_plugins.update!(size: 100.megabytes)
            end

            it_behaves_like 'returning an error service response', message: 'Metadata file for plugins is too big'
          end

          context 'an error from the create versions xml service' do
            let(:create_plugins_xml_service_response) { ServiceResponse.error(message: 'metadata_content is invalid') }

            before do
              expect(::Packages::Maven::Metadata::CreateVersionsXmlService).not_to receive(:new)
              expect(::Packages::Maven::Metadata::AppendPackageFileService).not_to receive(:new)
            end

            it_behaves_like 'returning an error service response', message: 'metadata_content is invalid'
          end

          context 'an error from the append package file service' do
            let(:create_plugins_xml_service_response) { ServiceResponse.success(payload: { changes_exist: true, empty_plugins: false, metadata_content: 'new metadata' }) }
            let(:append_package_file_service_response) { ServiceResponse.error(message: 'metadata content is not set') }

            before do
              expect(::Packages::Maven::Metadata::CreateVersionsXmlService).not_to receive(:new)
            end

            it_behaves_like 'returning an error service response', message: 'metadata content is not set'
          end

          context 'without a versionless package for plugins' do
            before do
              versionless_package_for_plugins.package_files.update_all(file_name: 'test.txt')
              expect(::Packages::Maven::Metadata::CreatePluginsXmlService).not_to receive(:new)
            end

            it_behaves_like 'returning a success service response', message: 'New metadata package files created'
          end

          context 'without a versionless package for versions' do
            before do
              versionless_package_for_versions.package_files.update_all(file_name: 'test.txt')
              expect(::Packages::Maven::Metadata::CreateVersionsXmlService).not_to receive(:new)
            end

            it_behaves_like 'returning a success service response', message: 'No changes for plugins xml'
          end

          context 'without a metadata package file for plugins' do
            before do
              versionless_package_for_plugins.package_files.update_all(file_name: 'test.txt')
              expect(::Packages::Maven::Metadata::CreatePluginsXmlService).not_to receive(:new)
            end

            it_behaves_like 'returning a success service response', message: 'New metadata package files created'
          end
        end
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true

module Packages
  module Maven
    module Metadata
      class CreateVersionsXmlService < BaseCreateXmlService
        XPATH_VERSIONING = '//metadata/versioning'
        XPATH_VERSIONS = '//versions'
        XPATH_VERSION = '//version'
        XPATH_LATEST = '//latest'
        XPATH_RELEASE = '//release'
        XPATH_LAST_UPDATED = '//lastUpdated'

        EMPTY_VERSIONS_PAYLOAD = {
          changes_exist: true,
          empty_versions: true
        }.freeze

        def execute
          return ServiceResponse.error(message: 'package not set') unless @package
          return ServiceResponse.error(message: 'metadata_content not set') unless @metadata_content
          return ServiceResponse.error(message: 'metadata_content is invalid') unless valid_metadata_content?
          return ServiceResponse.success(payload: EMPTY_VERSIONS_PAYLOAD) if versions_from_database.empty?

          changes_exist = false
          changes_exist = true if update_versions_list
          changes_exist = true if update_latest
          changes_exist = true if update_release
          update_last_updated_timestamp if changes_exist

          payload = { changes_exist: changes_exist, empty_versions: false }
          payload[:metadata_content] = xml_doc.to_xml(indent: INDENT_SPACE) if changes_exist

          ServiceResponse.success(payload: payload)
        end

        private

        def valid_metadata_content?
          versioning_xml_node.present? &&
            versions_xml_node.present? &&
            last_updated_xml_node.present?
        end

        def update_versions_list
          return false if versions_from_xml == versions_from_database

          version_xml_nodes.remove

          versions_from_database.each do |version|
            versions_xml_node.add_child(xml_node('version', version))
          end
          true
        end

        def update_latest
          return false if latest_coherent?

          latest_xml_node.content = latest_from_database
          true
        end

        def latest_coherent?
          latest_from_xml.nil? || latest_from_xml == latest_from_database
        end

        def update_release
          return false if release_coherent?

          unless release_xml_node.present?
            log_malformed_content('Missing release tag')

            return false
          end

          if release_from_database
            release_xml_node.content = release_from_database
          else
            release_xml_node.remove
          end

          true
        end

        def release_coherent?
          release_from_xml == release_from_database
        end

        def update_last_updated_timestamp
          last_updated_xml_node.content = Time.zone.now.strftime('%Y%m%d%H%M%S')
        end

        def versioning_xml_node
          xml_doc.xpath(XPATH_VERSIONING).first
        end
        strong_memoize_attr :versioning_xml_node

        def versions_xml_node
          versioning_xml_node&.xpath(XPATH_VERSIONS)
                               &.first
        end
        strong_memoize_attr :versions_xml_node

        def version_xml_nodes
          versions_xml_node&.xpath(XPATH_VERSION)
        end

        def latest_xml_node
          versioning_xml_node&.xpath(XPATH_LATEST)
                               &.first
        end
        strong_memoize_attr :latest_xml_node

        def release_xml_node
          versioning_xml_node&.xpath(XPATH_RELEASE)
                               &.first
        end
        strong_memoize_attr :release_xml_node

        def last_updated_xml_node
          versioning_xml_node.xpath(XPATH_LAST_UPDATED)
                               .first
        end
        strong_memoize_attr :last_updated_xml_node

        def versions_from_xml
          versions_xml_node.xpath(XPATH_VERSION)
                             .map(&:text)
        end
        strong_memoize_attr :versions_from_xml

        def latest_from_xml
          latest_xml_node&.text
        end

        def release_from_xml
          release_xml_node&.text
        end

        def versions_from_database
          @package.project.packages
                            .maven
                            .displayable
                            .with_name(@package.name)
                            .has_version
                            .order_created
                            .pluck_versions
        end
        strong_memoize_attr :versions_from_database

        def latest_from_database
          versions_from_database.last
        end

        def release_from_database
          non_snapshot_versions_from_database = versions_from_database.reject { |v| v.ends_with?('SNAPSHOT') }
          non_snapshot_versions_from_database.last
        end
        strong_memoize_attr :release_from_database

        def log_malformed_content(reason)
          logger.warn(
            message: 'A malformed metadata file has been encountered',
            reason: reason,
            project_id: @package.project_id,
            package_id: @package.id
          )
        end
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe ::Packages::Maven::Metadata::CreateVersionsXmlService, feature_category: :package_registry do
  let_it_be(:package) { create(:maven_package, version: nil) }

  let(:versions_in_database) { %w[1.3 2.0-SNAPSHOT 1.6 1.4 1.5-SNAPSHOT] }
  let(:versions_in_xml) { %w[1.3 2.0-SNAPSHOT 1.6 1.4 1.5-SNAPSHOT] }
  let(:version_latest) { nil }
  let(:version_release) { '1.4' }
  let(:service) { described_class.new(metadata_content: metadata_xml, package: package) }

  describe '#execute' do
    subject { service.execute }

    before do
      next unless package

      versions_in_database.each do |version|
        create(:maven_package, name: package.name, version: version, project: package.project)
      end
    end

    shared_examples 'returning an xml with versions in the database' do
      it 'returns an metadata versions xml with versions in the database', :aggregate_failures do
        result = subject

        expect(result).to be_success
        expect(versions_from(result.payload[:metadata_content])).to match_array(versions_in_database)
      end
    end

    shared_examples 'returning an xml with' do |release:, latest:|
      it 'returns an xml with the updated release and latest versions', :aggregate_failures do
        result = subject

        expect(result).to be_success
        expect(result.payload[:changes_exist]).to be_truthy
        xml = result.payload[:metadata_content]
        expect(release_from(xml)).to eq(release)
        expect(latest_from(xml)).to eq(latest)
      end
    end

    context 'with same versions in both sides' do
      it 'returns no changes', :aggregate_failures do
        result = subject

        expect(result).to be_success
        expect(result.payload).to eq(changes_exist: false, empty_versions: false)
      end
    end

    context 'with more versions' do
      let(:additional_versions) { %w[5.5 5.6 5.7-SNAPSHOT] }

      context 'in the xml side' do
        let(:versions_in_xml) { versions_in_database + additional_versions }

        it_behaves_like 'returning an xml with versions in the database'
      end

      context 'in the database side' do
        let(:versions_in_database) { versions_in_xml + additional_versions }

        it_behaves_like 'returning an xml with versions in the database'

        context 'with an xml without a release version' do
          let(:version_release) { nil }

          it_behaves_like 'returning an xml with versions in the database'

          it 'logs a warn with the reason' do
            expect(Gitlab::AppJsonLogger).to receive(:warn).with(
              message: 'A malformed metadata file has been encountered',
              reason: 'Missing release tag',
              project_id: package.project_id,
              package_id: package.id
            )

            subject
          end
        end
      end
    end

    context 'with completely different versions' do
      let(:versions_in_database) { %w[1.0 1.1 1.2] }
      let(:versions_in_xml) { %w[2.0 2.1 2.2] }

      it_behaves_like 'returning an xml with versions in the database'
    end

    context 'with no versions in the database' do
      let(:versions_in_database) { [] }

      it 'returns a success', :aggregate_failures do
        result = subject

        expect(result).to be_success
        expect(result.payload).to eq(changes_exist: true, empty_versions: true)
      end

      context 'with an xml without a release version' do
        let(:version_release) { nil }

        it 'returns a success', :aggregate_failures do
          result = subject

          expect(result).to be_success
          expect(result.payload).to eq(changes_exist: true, empty_versions: true)
        end
      end
    end

    context 'with differences in both sides' do
      let(:shared_versions) { %w[1.3 2.0-SNAPSHOT 1.6 1.4 1.5-SNAPSHOT] }
      let(:additional_versions_in_xml) { %w[5.5 5.6 5.7-SNAPSHOT] }
      let(:versions_in_xml) { shared_versions + additional_versions_in_xml }
      let(:additional_versions_in_database) { %w[6.5 6.6 6.7-SNAPSHOT] }
      let(:versions_in_database) { shared_versions + additional_versions_in_database }

      it_behaves_like 'returning an xml with versions in the database'
    end

    context 'with a new release and latest from the database' do
      let(:versions_in_database) { versions_in_xml + %w[4.1 4.2-SNAPSHOT] }

      it_behaves_like 'returning an xml with', release: '4.1', latest: nil

      context 'with a latest in the xml' do
        let(:version_latest) { '1.6' }

        it_behaves_like 'returning an xml with', release: '4.1', latest: '4.2-SNAPSHOT'
      end
    end

    context 'with release and latest not existing in the database' do
      let(:version_release) { '7.0' }
      let(:version_latest) { '8.0-SNAPSHOT' }

      it_behaves_like 'returning an xml with', release: '1.4', latest: '1.5-SNAPSHOT'
    end

    context 'with added versions in the database side no more recent than release' do
      let(:versions_in_database) { versions_in_xml + %w[4.1 4.2-SNAPSHOT] }

      before do
        ::Packages::Package.find_by(name: package.name, version: '4.1').update!(created_at: 2.weeks.ago)
        ::Packages::Package.find_by(name: package.name, version: '4.2-SNAPSHOT').update!(created_at: 2.weeks.ago)
      end

      it_behaves_like 'returning an xml with', release: '1.4', latest: nil

      context 'with a latest in the xml' do
        let(:version_latest) { '1.6' }

        it_behaves_like 'returning an xml with', release: '1.4', latest: '1.5-SNAPSHOT'
      end
    end

    context 'only snapshot versions are in the database' do
      let(:versions_in_database) { %w[4.2-SNAPSHOT] }

      it_behaves_like 'returning an xml with', release: nil, latest: nil

      it 'returns an xml without any release element' do
        result = subject

        xml_doc = Nokogiri::XML(result.payload[:metadata_content])
        expect(xml_doc.xpath('//metadata/versioning/release')).to be_empty
      end
    end

    context 'last updated timestamp' do
      let(:versions_in_database) { versions_in_xml + %w[4.1 4.2-SNAPSHOT] }

      it 'updates the last updated timestamp' do
        original = last_updated_from(metadata_xml)

        result = subject

        expect(result).to be_success
        expect(original).not_to eq(last_updated_from(result.payload[:metadata_content]))
      end
    end

    context 'with an incomplete metadata content' do
      let(:metadata_xml) { '<metadata></metadata>' }

      it_behaves_like 'returning an error service response', message: 'metadata_content is invalid'
    end

    context 'with an invalid metadata content' do
      let(:metadata_xml) { '<meta></metadata>' }

      it_behaves_like 'returning an error service response', message: 'metadata_content is invalid'
    end

    it_behaves_like 'handling metadata content pointing to a file for the create xml service'

    it_behaves_like 'handling invalid parameters for create xml service'
  end

  def metadata_xml
    Nokogiri::XML::Builder.new do |xml|
      xml.metadata do
        xml.groupId(package.maven_metadatum.app_group)
        xml.artifactId(package.maven_metadatum.app_name)
        xml.versioning do
          xml.release(version_release) if version_release
          xml.latest(version_latest) if version_latest
          xml.lastUpdated('20210113130531')
          xml.versions do
            versions_in_xml.each do |version|
              xml.version(version)
            end
          end
        end
      end
    end.to_xml
  end

  def versions_from(xml_content)
    doc = Nokogiri::XML(xml_content)
    doc.xpath('//metadata/versioning/versions/version').map(&:content)
  end

  def release_from(xml_content)
    doc = Nokogiri::XML(xml_content)
    doc.xpath('//metadata/versioning/release').first&.content
  end

  def latest_from(xml_content)
    doc = Nokogiri::XML(xml_content)
    doc.xpath('//metadata/versioning/latest').first&.content
  end

  def last_updated_from(xml_content)
    doc = Nokogiri::XML(xml_content)
    doc.xpath('//metadata/versioning/lastUpdated').first.content
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true

module Packages
  module Composer
    class ComposerJsonService
      InvalidJson = Class.new(StandardError)

      def initialize(project, target)
        @project = project
        @target = target
      end

      def execute
        composer_json
      end

      private

      def composer_json
        composer_file = @project.repository.blob_at(@target, 'composer.json')

        composer_file_not_found! unless composer_file

        Gitlab::Json.parse(composer_file.data)
      rescue JSON::ParserError
        raise InvalidJson, 'Could not parse composer.json file. Invalid JSON.'
      end

      def composer_file_not_found!
        raise InvalidJson, 'The file composer.json was not found.'
      end
    end
  end
end

```

Response:
# frozen_string_literal: true
require 'spec_helper'

RSpec.describe Packages::Composer::ComposerJsonService, feature_category: :package_registry do
  describe '#execute' do
    let(:branch) { project.repository.find_branch('master') }
    let(:target) { branch.target }

    subject { described_class.new(project, target).execute }

    context 'with an existing file' do
      let(:project) { create(:project, :custom_repo, files: { 'composer.json' => json }) }

      context 'with a valid file' do
        let(:json) { '{ "name": "package-name"}' }

        it 'returns the parsed json' do
          expect(subject).to eq({ 'name' => 'package-name' })
        end
      end

      context 'with an invalid file' do
        let(:json) { '{ name": "package-name"}' }

        it 'raises an error' do
          expect { subject }.to raise_error(described_class::InvalidJson, /Invalid/)
        end
      end
    end

    context 'without the composer.json file' do
      let(:project) { create(:project, :repository) }

      it 'raises an error' do
        expect { subject }.to raise_error(described_class::InvalidJson, /not found/)
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true

module Packages
  module Composer
    class CreatePackageService < ::Packages::CreatePackageService
      include ::Gitlab::Utils::StrongMemoize

      def execute
        # fetches json outside of transaction
        composer_json

        ::Packages::Package.transaction do
          ::Packages::Composer::Metadatum.upsert({
            package_id: created_package.id,
            target_sha: target,
            composer_json: composer_json
          })
        end

        created_package
      end

      private

      def created_package
        find_or_create_package!(:composer, name: package_name, version: package_version)
      end

      def composer_json
        ::Packages::Composer::ComposerJsonService.new(project, target).execute
      end
      strong_memoize_attr :composer_json

      def package_name
        composer_json['name']
      end

      def target
        (branch || tag).target
      end

      def branch
        params[:branch]
      end

      def tag
        params[:tag]
      end

      def package_version
        ::Packages::Composer::VersionParserService.new(tag_name: tag&.name, branch_name: branch&.name).execute
      end
    end
  end
end

```

Response:
# frozen_string_literal: true
require 'spec_helper'

RSpec.describe Packages::Composer::CreatePackageService, feature_category: :package_registry do
  include PackagesManagerApiSpecHelpers

  let_it_be(:package_name) { 'composer-package-name' }
  let_it_be(:json) { { name: package_name }.to_json }
  let_it_be(:project) { create(:project, :custom_repo, files: { 'composer.json' => json }) }
  let_it_be(:user) { create(:user) }

  let(:params) do
    {
      branch: branch,
      tag: tag
    }
  end

  describe '#execute' do
    let(:tag) { nil }
    let(:branch) { nil }

    subject { described_class.new(project, user, params).execute }

    let(:created_package) { Packages::Package.composer.last }

    context 'without an existing package' do
      context 'with a branch' do
        let(:branch) { project.repository.find_branch('master') }

        it 'creates the package' do
          expect { subject }
            .to change { Packages::Package.composer.count }.by(1)
            .and change { Packages::Composer::Metadatum.count }.by(1)

          expect(created_package.name).to eq package_name
          expect(created_package.version).to eq 'dev-master'
          expect(created_package.composer_metadatum.target_sha).to eq branch.target
          expect(created_package.composer_metadatum.composer_json.to_json).to eq json
        end

        it_behaves_like 'assigns the package creator' do
          let(:package) { created_package }
        end

        it_behaves_like 'assigns build to package'
        it_behaves_like 'assigns status to package'
      end

      context 'with a tag' do
        let(:tag) { project.repository.find_tag('v1.2.3') }

        before_all do
          project.repository.add_tag(user, 'v1.2.3', 'master')
        end

        it 'creates the package' do
          expect { subject }
            .to change { Packages::Package.composer.count }.by(1)
            .and change { Packages::Composer::Metadatum.count }.by(1)

          expect(created_package.name).to eq package_name
          expect(created_package.version).to eq '1.2.3'
        end

        it_behaves_like 'assigns the package creator' do
          let(:package) { created_package }
        end

        it_behaves_like 'assigns build to package'
        it_behaves_like 'assigns status to package'
      end
    end

    context 'with an existing package' do
      let(:branch) { project.repository.find_branch('master') }

      context 'belonging to the same project' do
        before do
          described_class.new(project, user, params).execute
        end

        it 'does not create a new package' do
          expect { subject }
            .to change { Packages::Package.composer.count }.by(0)
            .and change { Packages::Composer::Metadatum.count }.by(0)
        end
      end

      context 'belonging to another project' do
        let(:other_project) { create(:project) }
        let!(:other_package) { create(:composer_package, name: package_name, version: 'dev-master', project: other_project) }

        it 'fails with an error' do
          expect { subject }
            .to raise_error(/is already taken/)
        end

        context 'with pending_destruction package' do
          let!(:other_package) { create(:composer_package, :pending_destruction, name: package_name, version: 'dev-master', project: other_project) }

          it 'creates the package' do
            expect { subject }
              .to change { Packages::Package.composer.count }.by(1)
              .and change { Packages::Composer::Metadatum.count }.by(1)
          end
        end
      end

      context 'same name but of different type' do
        let(:other_project) { create(:project) }
        let!(:other_package) { create(:package, name: package_name, version: 'dev-master', project: other_project) }

        it 'creates the package' do
          expect { subject }
            .to change { Packages::Package.composer.count }.by(1)
            .and change { Packages::Composer::Metadatum.count }.by(1)
        end
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true

module Packages
  module Composer
    class VersionParserService
      def initialize(tag_name: nil, branch_name: nil)
        @tag_name = tag_name
        @branch_name = branch_name
      end

      def execute
        if @tag_name.present?
          @tag_name.delete_prefix('v')
        elsif @branch_name.present?
          branch_suffix_or_prefix(@branch_name.match(Gitlab::Regex.composer_package_version_regex))
        end
      end

      private

      def branch_suffix_or_prefix(match)
        if match
          captures = match.captures.reject(&:blank?)
          if captures[-1] == '.x'
            captures[0] + '-dev'
          else
            captures[0] + '.x-dev'
          end
        else
          "dev-#{@branch_name}"
        end
      end
    end
  end
end

```

Response:
# frozen_string_literal: true
require 'spec_helper'

RSpec.describe Packages::Composer::VersionParserService, feature_category: :package_registry do
  let_it_be(:params) { {} }

  describe '#execute' do
    using RSpec::Parameterized::TableSyntax

    subject { described_class.new(tag_name: tagname, branch_name: branchname).execute }

    where(:tagname, :branchname, :expected_version) do
      nil             | 'master'     | 'dev-master'
      nil             | 'my-feature' | 'dev-my-feature'
      nil             | '12-feature' | 'dev-12-feature'
      nil             | 'v1'         | '1.x-dev'
      nil             | 'v1.x'       | '1.x-dev'
      nil             | 'v1.7.x'     | '1.7.x-dev'
      nil             | 'v1.7'       | '1.7.x-dev'
      nil             | '1.7.x'      | '1.7.x-dev'
      'v1.0.0'        | nil          | '1.0.0'
      'v1.0'          | nil          | '1.0'
      'v1.0.1+meta'   | nil          | '1.0.1+meta'
      '1.0'           | nil          | '1.0'
      '1.0.2'         | nil          | '1.0.2'
      '1.0.2-beta2'   | nil          | '1.0.2-beta2'
      '1.0.1+meta'    | nil          | '1.0.1+meta'
    end

    with_them do
      it { is_expected.to eq expected_version }
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true

module Packages
  module Rubygems
    class DependencyResolverService < BaseService
      include Gitlab::Utils::StrongMemoize

      DEFAULT_PLATFORM = 'ruby'

      def execute
        unless Ability.allowed?(current_user, :read_package, project&.packages_policy_subject)
          return ServiceResponse.error(message: "forbidden", http_status: :forbidden)
        end

        return ServiceResponse.error(message: "#{gem_name} not found", http_status: :not_found) if packages.empty?

        payload = packages.map do |package|
          dependencies = package.dependency_links.map do |link|
            [link.dependency.name, link.dependency.version_pattern]
          end

          {
            name: gem_name,
            number: package.version,
            platform: DEFAULT_PLATFORM,
            dependencies: dependencies
          }
        end

        ServiceResponse.success(payload: payload)
      end

      private

      def packages
        project.packages.with_name(gem_name)
      end
      strong_memoize_attr :packages

      def gem_name
        params[:gem_name]
      end
    end
  end
end

```

Response:
# frozen_string_literal: true
require 'spec_helper'

RSpec.describe Packages::Rubygems::DependencyResolverService, feature_category: :package_registry do
  let_it_be(:project) { create(:project, :private) }
  let_it_be(:package) { create(:package, project: project) }
  let_it_be(:user) { create(:user) }

  let(:gem_name) { package.name }
  let(:service) { described_class.new(project, user, gem_name: gem_name) }

  describe '#execute' do
    subject { service.execute }

    context 'user without access' do
      it 'returns a service error' do
        expect(subject.error?).to be(true)
        expect(subject.message).to eq('forbidden')
      end
    end

    context 'user with access' do
      before do
        project.add_developer(user)
      end

      context 'when no package is found' do
        let(:gem_name) { nil }

        it 'returns a service error', :aggregate_failures do
          expect(subject.error?).to be(true)
          expect(subject.message).to eq("#{gem_name} not found")
        end
      end

      context 'package without dependencies' do
        it 'returns an empty dependencies array' do
          expected_result = [{
            name: package.name,
            number: package.version,
            platform: described_class::DEFAULT_PLATFORM,
            dependencies: []
          }]

          expect(subject.payload).to eq(expected_result)
        end
      end

      context 'package with dependencies' do
        let(:dependency_link) { create(:packages_dependency_link, :rubygems, package: package) }
        let(:dependency_link2) { create(:packages_dependency_link, :rubygems, package: package) }
        let(:dependency_link3) { create(:packages_dependency_link, :rubygems, package: package) }

        it 'returns a set of dependencies' do
          expected_result = [{
            name: package.name,
            number: package.version,
            platform: described_class::DEFAULT_PLATFORM,
            dependencies: [
              [dependency_link.dependency.name, dependency_link.dependency.version_pattern],
              [dependency_link2.dependency.name, dependency_link2.dependency.version_pattern],
              [dependency_link3.dependency.name, dependency_link3.dependency.version_pattern]
            ]
          }]

          expect(subject.payload).to eq(expected_result)
        end
      end

      context 'package with multiple versions' do
        let(:dependency_link) { create(:packages_dependency_link, :rubygems, package: package) }
        let(:dependency_link2) { create(:packages_dependency_link, :rubygems, package: package) }
        let(:dependency_link3) { create(:packages_dependency_link, :rubygems, package: package) }
        let(:package2) { create(:package, project: project, name: package.name, version: '9.9.9') }
        let(:dependency_link4) { create(:packages_dependency_link, :rubygems, package: package2) }

        it 'returns a set of dependencies' do
          expected_result = [{
            name: package.name,
            number: package.version,
            platform: described_class::DEFAULT_PLATFORM,
            dependencies: [
              [dependency_link.dependency.name, dependency_link.dependency.version_pattern],
              [dependency_link2.dependency.name, dependency_link2.dependency.version_pattern],
              [dependency_link3.dependency.name, dependency_link3.dependency.version_pattern]
            ]
          }, {
            name: package2.name,
            number: package2.version,
            platform: described_class::DEFAULT_PLATFORM,
            dependencies: [
              [dependency_link4.dependency.name, dependency_link4.dependency.version_pattern]
            ]
          }]

          expect(subject.payload).to match_array(expected_result)
        end
      end
    end
  end
end