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

module Packages
  module Nuget
    class UpdatePackageFromMetadataService
      include Gitlab::Utils::StrongMemoize
      include ExclusiveLeaseGuard

      # used by ExclusiveLeaseGuard
      DEFAULT_LEASE_TIMEOUT = 1.hour.to_i.freeze
      SYMBOL_PACKAGE_IDENTIFIER = 'SymbolsPackage'
      INVALID_METADATA_ERROR_MESSAGE = 'package name, version, authors and/or description not found in metadata'
      INVALID_METADATA_ERROR_SYMBOL_MESSAGE = 'package name, version and/or description not found in metadata'
      MISSING_MATCHING_PACKAGE_ERROR_MESSAGE = 'symbol package is invalid, matching package does not exist'

      InvalidMetadataError = ZipError = Class.new(StandardError)

      def initialize(package_file, package_zip_file)
        @package_file = package_file
        @package_zip_file = package_zip_file
      end

      def execute
        unless valid_metadata?
          error_message = symbol_package? ? INVALID_METADATA_ERROR_SYMBOL_MESSAGE : INVALID_METADATA_ERROR_MESSAGE
          raise InvalidMetadataError, error_message
        end

        try_obtain_lease do
          @package_file.transaction do
            process_package_update
          end
        end
      rescue ActiveRecord::RecordInvalid => e
        raise InvalidMetadataError, e.message
      rescue Zip::Error
        raise ZipError, 'Could not open the .nupkg file'
      end

      private

      def process_package_update
        package_to_destroy = nil
        target_package = @package_file.package

        if existing_package
          package_to_destroy = @package_file.package
          target_package = existing_package
        else
          if symbol_package?
            raise InvalidMetadataError, MISSING_MATCHING_PACKAGE_ERROR_MESSAGE
          end

          update_linked_package
        end

        build_infos = package_to_destroy&.build_infos || []

        update_package(target_package, build_infos)
        create_symbol_files
        ::Packages::UpdatePackageFileService.new(@package_file, package_id: target_package.id, file_name: package_filename)
                                            .execute
        package_to_destroy&.destroy!
      end

      def update_package(package, build_infos)
        return if symbol_package?

        ::Packages::Nuget::SyncMetadatumService
          .new(package, metadata.slice(:authors, :description, :project_url, :license_url, :icon_url))
          .execute

        ::Packages::UpdateTagsService
          .new(package, package_tags)
          .execute

        package.build_infos << build_infos if build_infos.any?
      rescue StandardError => e
        raise InvalidMetadataError, e.message
      end

      def create_symbol_files
        return unless symbol_package?

        ::Packages::Nuget::Symbols::CreateSymbolFilesService
          .new(existing_package, @package_zip_file)
          .execute
      end

      def valid_metadata?
        fields = [package_name, package_version, package_description]
        fields << package_authors unless symbol_package?
        fields.all?(&:present?)
      end

      def update_linked_package
        @package_file.package.update!(
          name: package_name,
          version: package_version,
          status: :default
        )

        ::Packages::Nuget::CreateDependencyService.new(@package_file.package, package_dependencies)
                                                  .execute
        @package_file.package
      end

      def existing_package
        ::Packages::Nuget::PackageFinder
          .new(
            nil,
            @package_file.project,
            package_name: package_name,
            package_version: package_version
          )
          .execute
          .first
      end
      strong_memoize_attr :existing_package

      def package_name
        metadata[:package_name]
      end

      def package_version
        metadata[:package_version]
      end

      def package_dependencies
        metadata.fetch(:package_dependencies, [])
      end

      def package_tags
        metadata.fetch(:package_tags, [])
      end

      def package_types
        metadata.fetch(:package_types, [])
      end

      def package_authors
        metadata[:authors]
      end

      def package_description
        metadata[:description]
      end

      def symbol_package?
        package_types.include?(SYMBOL_PACKAGE_IDENTIFIER)
      end
      strong_memoize_attr :symbol_package?

      def metadata
        ::Packages::Nuget::MetadataExtractionService.new(@package_zip_file).execute.payload
      end
      strong_memoize_attr :metadata

      def package_filename
        "#{package_name.downcase}.#{package_version.downcase}.#{symbol_package? ? 'snupkg' : 'nupkg'}"
      end

      # used by ExclusiveLeaseGuard
      def lease_key
        package_id = existing_package ? existing_package.id : @package_file.package_id
        "packages:nuget:update_package_from_metadata_service:package:#{package_id}"
      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::Nuget::UpdatePackageFromMetadataService, :clean_gitlab_redis_shared_state, feature_category: :package_registry do
  include ExclusiveLeaseHelpers

  let!(:package) { create(:nuget_package, :processing, :with_symbol_package, :with_build) }
  let(:package_file) { package.package_files.first }
  let(:package_zip_file) { Zip::File.new(package_file.file) }
  let(:service) { described_class.new(package_file, package_zip_file) }
  let(:package_name) { 'DummyProject.DummyPackage' }
  let(:package_version) { '1.0.0' }
  let(:package_file_name) { 'dummyproject.dummypackage.1.0.0.nupkg' }

  shared_examples 'raising an' do |error_class, with_message:|
    it "raises an #{error_class}" do
      expect { subject }.to raise_error(error_class, with_message)
    end
  end

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

    subject { service.execute }

    shared_examples 'taking the lease' do
      before do
        allow(service).to receive(:lease_release?).and_return(false)
      end

      it 'takes the lease' do
        expect(service).to receive(:try_obtain_lease).and_call_original

        subject

        expect(service.exclusive_lease.exists?).to be_truthy
      end
    end

    shared_examples 'not updating the package if the lease is taken' do
      context 'without obtaining the exclusive lease' do
        let(:lease_key) { "packages:nuget:update_package_from_metadata_service:package:#{package_id}" }
        let(:metadata) { { package_name: package_name, package_version: package_version, authors: 'author1, author2', description: 'test description' } }
        let(:package_from_package_file) { package_file.package }

        before do
          stub_exclusive_lease_taken(lease_key, timeout: 1.hour)
          # to allow the above stub, we need to stub the metadata function as the
          # original implementation will try to get an exclusive lease on the
          # file in object storage
          allow(service).to receive(:metadata).and_return(metadata)
        end

        it 'does not update the package', :aggregate_failures do
          expect(service).to receive(:try_obtain_lease).and_call_original

          expect { subject }
            .to change { ::Packages::Package.count }.by(0)
            .and change { Packages::DependencyLink.count }.by(0)
          expect(package_file.reload.file_name).not_to eq(package_file_name)
          expect(package_file.package).to be_processing
          expect(package_file.package.reload.name).not_to eq(package_name)
          expect(package_file.package.version).not_to eq(package_version)
        end
      end
    end

    context 'with no existing package' do
      let(:package_id) { package.id }

      it 'updates package and package file and creates metadatum', :aggregate_failures do
        expect { subject }
          .to not_change { ::Packages::Package.count }
          .and change { Packages::Dependency.count }.by(1)
          .and change { Packages::DependencyLink.count }.by(1)
          .and change { ::Packages::Nuget::Metadatum.count }.by(1)

        expect(package.reload.name).to eq(package_name)
        expect(package.version).to eq(package_version)
        expect(package).to be_default
        expect(package_file.reload.file_name).to eq(package_file_name)
        # hard reset needed to properly reload package_file.file
        expect(Packages::PackageFile.find(package_file.id).file.size).not_to eq 0
      end

      it_behaves_like 'taking the lease'

      it_behaves_like 'not updating the package if the lease is taken'
    end

    context 'with existing package' do
      let!(:existing_package) { create(:nuget_package, project: package.project, name: package_name, version: package_version) }
      let(:package_id) { existing_package.id }

      it 'link existing package and updates package file', :aggregate_failures do
        expect(service).to receive(:try_obtain_lease).and_call_original

        expect { subject }
          .to change { ::Packages::Package.count }.by(-1)
          .and change { Packages::Dependency.count }.by(0)
          .and change { Packages::DependencyLink.count }.by(0)
          .and change { Packages::Nuget::DependencyLinkMetadatum.count }.by(0)
          .and change { ::Packages::Nuget::Metadatum.count }.by(1)
          .and change { existing_package.build_infos.count }.by(1)
        expect(package_file.reload.file_name).to eq(package_file_name)
        expect(package_file.package).to eq(existing_package)
      end

      it_behaves_like 'taking the lease'

      it_behaves_like 'not updating the package if the lease is taken'

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

        it 'reuses the processing package', :aggregate_failures do
          expect { subject }
            .to not_change { ::Packages::Package.count }
            .and change { Packages::Dependency.count }.by(1)
            .and change { Packages::DependencyLink.count }.by(1)
            .and change { ::Packages::Nuget::Metadatum.count }.by(1)
        end
      end
    end

    context 'with a nuspec file with metadata' do
      let(:nuspec_filepath) { 'packages/nuget/with_metadata.nuspec' }
      let(:expected_tags) { %w[foo bar test tag1 tag2 tag3 tag4 tag5] }

      before do
        allow_next_instance_of(Packages::Nuget::MetadataExtractionService) do |service|
          allow(service)
            .to receive(:nuspec_file_content).and_return(fixture_file(nuspec_filepath))
        end
      end

      it 'creates tags' do
        expect(service).to receive(:try_obtain_lease).and_call_original
        expect { subject }.to change { ::Packages::Tag.count }.by(8)
        expect(package.reload.tags.map(&:name)).to contain_exactly(*expected_tags)
      end

      context 'with existing package and tags' do
        let!(:existing_package) { create(:nuget_package, project: package.project, name: 'DummyProject.WithMetadata', version: '1.2.3') }
        let!(:tag1) { create(:packages_tag, package: existing_package, name: 'tag1') }
        let!(:tag2) { create(:packages_tag, package: existing_package, name: 'tag2') }
        let!(:tag3) { create(:packages_tag, package: existing_package, name: 'tag_not_in_metadata') }

        it 'creates tags and deletes those not in metadata' do
          expect(service).to receive(:try_obtain_lease).and_call_original
          expect { subject }.to change { ::Packages::Tag.count }.by(5)
          expect(existing_package.tags.map(&:name)).to contain_exactly(*expected_tags)
        end
      end

      it 'creates nuget metadatum', :aggregate_failures do
        expect { subject }
          .to not_change { ::Packages::Package.count }
          .and change { ::Packages::Nuget::Metadatum.count }.by(1)

        metadatum = package_file.reload.package.nuget_metadatum
        expect(metadatum.authors).to eq('Author Test')
        expect(metadatum.description).to eq('Description Test')
        expect(metadatum.license_url).to eq('https://opensource.org/licenses/MIT')
        expect(metadatum.project_url).to eq('https://gitlab.com/gitlab-org/gitlab')
        expect(metadatum.icon_url).to eq('https://opensource.org/files/osi_keyhole_300X300_90ppi_0.png')
      end

      context 'with too long url' do
        let_it_be(:too_long_url) { "http://localhost/#{'bananas' * 50}" }

        let(:metadata) { { package_name: package_name, package_version: package_version, authors: 'Author Test', description: 'Description Test', license_url: too_long_url } }

        before do
          allow(service).to receive(:metadata).and_return(metadata)
        end

        it_behaves_like 'raising an', described_class::InvalidMetadataError, with_message: /Validation failed: License url is too long/
      end

      context 'without authors or description' do
        %i[authors description].each do |property|
          context "for #{property}" do
            let(:metadata) { { package_name: package_name, package_version: package_version, property => nil } }

            before do
              allow(service).to receive(:metadata).and_return(metadata)
            end

            it_behaves_like 'raising an', described_class::InvalidMetadataError, with_message: described_class::INVALID_METADATA_ERROR_MESSAGE
          end
        end
      end
    end

    context 'with nuspec file with dependencies' do
      let(:nuspec_filepath) { 'packages/nuget/with_dependencies.nuspec' }
      let(:package_name) { 'Test.Package' }
      let(:package_version) { '3.5.2' }
      let(:package_file_name) { 'test.package.3.5.2.nupkg' }

      before do
        allow_next_instance_of(Packages::Nuget::MetadataExtractionService) do |service|
          allow(service)
            .to receive(:nuspec_file_content).and_return(fixture_file(nuspec_filepath))
        end
      end

      it 'updates package and package file', :aggregate_failures do
        expect { subject }
          .to not_change { ::Packages::Package.count }
          .and change { Packages::Dependency.count }.by(4)
          .and change { Packages::DependencyLink.count }.by(4)
          .and change { Packages::Nuget::DependencyLinkMetadatum.count }.by(2)

        expect(package.reload.name).to eq(package_name)
        expect(package.version).to eq(package_version)
        expect(package).to be_default
        expect(package_file.reload.file_name).to eq(package_file_name)
        # hard reset needed to properly reload package_file.file
        expect(Packages::PackageFile.find(package_file.id).file.size).not_to eq 0
      end
    end

    context 'with package file not containing a nuspec file' do
      before do
        allow_next_instance_of(Zip::File) do |file|
          allow(file).to receive(:glob).and_return([])
        end
      end

      it_behaves_like 'raising an', ::Packages::Nuget::ExtractMetadataFileService::ExtractionError, with_message: 'nuspec file not found'
    end

    context 'with a symbol package' do
      let(:package_file) { package.package_files.last }
      let(:package_file_name) { 'dummyproject.dummypackage.1.0.0.snupkg' }

      context 'with no existing package' do
        let(:package_id) { package.id }

        it_behaves_like 'raising an', described_class::InvalidMetadataError, with_message: described_class::MISSING_MATCHING_PACKAGE_ERROR_MESSAGE
      end

      context 'with existing package' do
        let!(:existing_package) { create(:nuget_package, project: package.project, name: package_name, version: package_version) }
        let(:package_id) { existing_package.id }
        let(:package_zip_file) do
          Zip::File.open(package_file.file.path) do |zipfile|
            zipfile.add('package.pdb', expand_fixture_path('packages/nuget/symbol/package.pdb'))
            zipfile
          end
        end

        it 'link existing package and updates package file', :aggregate_failures do
          expect(service).to receive(:try_obtain_lease).and_call_original
          expect(::Packages::Nuget::SyncMetadatumService).not_to receive(:new)
          expect(::Packages::UpdateTagsService).not_to receive(:new)
          expect_next_instance_of(Packages::Nuget::Symbols::CreateSymbolFilesService, existing_package, package_zip_file) do |service|
            expect(service).to receive(:execute).and_call_original
          end

          expect { subject }
            .to change { ::Packages::Package.count }.by(-1)
            .and change { Packages::Dependency.count }.by(0)
            .and change { Packages::DependencyLink.count }.by(0)
            .and change { Packages::Nuget::DependencyLinkMetadatum.count }.by(0)
            .and change { ::Packages::Nuget::Metadatum.count }.by(0)
            .and change { existing_package.nuget_symbols.count }.by(1)
          expect(package_file.reload.file_name).to eq(package_file_name)
          expect(package_file.package).to eq(existing_package)
        end

        it_behaves_like 'taking the lease'

        it_behaves_like 'not updating the package if the lease is taken'
      end
    end

    context 'with an invalid package name' do
      invalid_name_error_msg = 'Validation failed: Name is invalid'

      where(:invalid_name, :error_message) do
        ''                    | described_class::INVALID_METADATA_ERROR_MESSAGE
        'My/package'          | invalid_name_error_msg
        '../../../my_package' | invalid_name_error_msg
        '%2e%2e%2fmy_package' | invalid_name_error_msg
      end

      with_them do
        before do
          allow(service).to receive(:package_name).and_return(invalid_name)
        end

        it_behaves_like 'raising an', described_class::InvalidMetadataError, with_message: params[:error_message]
      end
    end

    context 'with an invalid package version' do
      invalid_version_error_msg = 'Validation failed: Version is invalid'

      where(:invalid_version, :error_message) do
        ''                     | described_class::INVALID_METADATA_ERROR_MESSAGE
        '555'                  | invalid_version_error_msg
        '1./2.3'               | invalid_version_error_msg
        '../../../../../1.2.3' | invalid_version_error_msg
        '%2e%2e%2f1.2.3'       | invalid_version_error_msg
      end

      with_them do
        before do
          allow(service).to receive(:package_version).and_return(invalid_version)
        end

        it_behaves_like 'raising an', described_class::InvalidMetadataError, with_message: params[:error_message]
      end
    end

    context 'with an invalid zip file' do
      before do
        allow_next_instance_of(::Packages::Nuget::MetadataExtractionService) do |instance|
          allow(instance).to receive(:execute).and_raise(Zip::Error)
        end
      end

      it_behaves_like 'raising an', described_class::ZipError, with_message: 'Could not open the .nupkg file'
    end
  end
end


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

module Packages
  module Nuget
    class CheckDuplicatesService < BaseService
      include Gitlab::Utils::StrongMemoize

      ExtractionError = Class.new(StandardError)

      def execute
        return ServiceResponse.success if package_settings_allow_duplicates? || !target_package_is_duplicate?

        ServiceResponse.error(
          message: 'A package with the same name and version already exists',
          reason: :conflict
        )
      rescue ExtractionError => e
        ServiceResponse.error(message: e.message, reason: :bad_request)
      end

      private

      def package_settings_allow_duplicates?
        package_settings.nuget_duplicates_allowed? || package_settings.class.duplicates_allowed?(existing_package)
      end

      def target_package_is_duplicate?
        existing_package.name.casecmp(metadata[:package_name]) == 0 &&
          (existing_package.version.casecmp(metadata[:package_version]) == 0 ||
            existing_package.normalized_nuget_version&.casecmp(metadata[:package_version]) == 0)
      end

      def package_settings
        project.namespace.package_settings
      end
      strong_memoize_attr :package_settings

      def existing_package
        ::Packages::Nuget::PackageFinder
          .new(
            current_user,
            project,
            package_name: metadata[:package_name],
            package_version: metadata[:package_version]
          )
          .execute
          .first
      end
      strong_memoize_attr :existing_package

      def metadata
        if params[:remote_url].present?
          ::Packages::Nuget::ExtractMetadataContentService
            .new(nuspec_file_content)
            .execute
            .payload
        else # to cover the case when package file is on disk not in object storage
          Zip::InputStream.open(params[:file]) do |zip|
            ::Packages::Nuget::MetadataExtractionService
              .new(zip)
              .execute
              .payload
          end
        end
      end
      strong_memoize_attr :metadata

      def nuspec_file_content
        ::Packages::Nuget::ExtractRemoteMetadataFileService
          .new(params[:remote_url])
          .execute
          .payload
      rescue ::Packages::Nuget::ExtractRemoteMetadataFileService::ExtractionError => e
        raise ExtractionError, e.message
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Packages::Nuget::CheckDuplicatesService, feature_category: :package_registry do
  let_it_be(:project) { create(:project) }
  let_it_be(:user) { create(:user) }
  let_it_be(:file_name) { 'package.nupkg' }

  let(:params) do
    {
      file_name: file_name,
      file: File.open(expand_fixture_path('packages/nuget/package.nupkg'))
    }
  end

  let(:service) { described_class.new(project, user, params) }

  describe '#execute' do
    subject(:execute) { service.execute }

    shared_examples 'returning error' do |reason:, message:|
      it 'returns an error' do
        response = execute

        expect(response.status).to eq(:error)
        expect(response.reason).to eq(reason)
        expect(response.message).to eq(message)
      end
    end

    shared_examples 'returning success' do
      it 'returns success' do
        response = execute

        expect(response.status).to eq(:success)
      end
    end

    shared_examples 'handling duplicates disallowed when package exists' do
      it_behaves_like 'returning error', reason: :conflict,
        message: 'A package with the same name and version already exists'

      context 'with nuget_duplicate_exception_regex' do
        before do
          package_settings.update_column(:nuget_duplicate_exception_regex, ".*#{existing_package.name.last(3)}.*")
        end

        it_behaves_like 'returning success'
      end
    end

    context 'with existing package' do
      let_it_be(:existing_package) { create(:nuget_package, :with_metadatum, project: project, version: '1.7.15.0') }
      let_it_be(:metadata) do
        {
          package_name: existing_package.name,
          package_version: existing_package.version,
          authors: 'authors',
          description: 'description'
        }
      end

      context 'when nuget duplicates are allowed' do
        before do
          allow_next_instance_of(Namespace::PackageSetting) do |instance|
            allow(instance).to receive(:nuget_duplicates_allowed?).and_return(true)
          end
        end

        it_behaves_like 'returning success'
      end

      context 'when nuget duplicates are not allowed' do
        let!(:package_settings) do
          create(:namespace_package_setting, :group, namespace: project.namespace, nuget_duplicates_allowed: false)
        end

        context 'when package file is in object storage' do
          let(:params) { super().merge(remote_url: 'https://example.com') }

          before do
            allow_next_instance_of(::Packages::Nuget::ExtractRemoteMetadataFileService) do |instance|
              allow(instance).to receive(:execute)
              .and_return(ServiceResponse.success(payload: Nokogiri::XML::Document.new))
            end
            allow_next_instance_of(::Packages::Nuget::ExtractMetadataContentService) do |instance|
              allow(instance).to receive(:execute).and_return(ServiceResponse.success(payload: metadata))
            end
          end

          it_behaves_like 'handling duplicates disallowed when package exists'

          context 'when ExtractRemoteMetadataFileService raises ExtractionError' do
            before do
              allow_next_instance_of(::Packages::Nuget::ExtractRemoteMetadataFileService) do |instance|
                allow(instance).to receive(:execute).and_raise(
                  ::Packages::Nuget::ExtractRemoteMetadataFileService::ExtractionError, 'nuspec file not found'
                )
              end
            end

            it_behaves_like 'returning error', reason: :bad_request, message: 'nuspec file not found'
          end

          context 'when version is normalized' do
            let(:metadata) { super().merge(package_version: '1.7.15') }

            it_behaves_like 'handling duplicates disallowed when package exists'
          end
        end

        context 'when package file is on disk' do
          before do
            allow_next_instance_of(::Packages::Nuget::MetadataExtractionService) do |instance|
              allow(instance).to receive(:execute).and_return(ServiceResponse.success(payload: metadata))
            end
          end

          it_behaves_like 'handling duplicates disallowed when package exists'
        end
      end
    end

    context 'with non existing package' do
      let_it_be(:metadata) do
        { package_name: 'foo', package_version: '1.0.0', authors: 'author', description: 'description' }
      end

      before do
        allow_next_instance_of(::Packages::Nuget::MetadataExtractionService) do |instance|
          allow(instance).to receive(:execute).and_return(ServiceResponse.success(payload: metadata))
        end
      end

      context 'when nuget duplicates are allowed' do
        let_it_be(:package_settings) do
          create(:namespace_package_setting, :group, namespace: project.namespace, nuget_duplicates_allowed: true)
        end

        it_behaves_like 'returning success'
      end

      context 'when nuget duplicates are not allowed' do
        let_it_be(:package_settings) do
          create(:namespace_package_setting, :group, namespace: project.namespace, nuget_duplicates_allowed: false)
        end

        it_behaves_like 'returning success'
      end
    end
  end
end


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

module Packages
  module Nuget
    class ProcessPackageFileService
      ExtractionError = Class.new(StandardError)

      def initialize(package_file)
        @package_file = package_file
      end

      def execute
        raise ExtractionError, 'invalid package file' unless valid_package_file?

        with_zip_file do |zip_file|
          ::Packages::Nuget::UpdatePackageFromMetadataService.new(package_file, zip_file).execute
        end
      end

      private

      attr_reader :package_file

      def valid_package_file?
        package_file && package_file.package&.nuget? && !package_file.file.empty_size?
      end

      def with_zip_file(&block)
        package_file.file.use_open_file(unlink_early: false) do |open_file|
          Zip::File.open(open_file.file_path, &block) # rubocop: disable Performance/Rubyzip
        end
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Packages::Nuget::ProcessPackageFileService, feature_category: :package_registry do
  let_it_be(:package_file) { build(:package_file, :nuget) }

  let(:service) { described_class.new(package_file) }

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

    shared_examples 'raises an error' do |error_message|
      it { expect { subject }.to raise_error(described_class::ExtractionError, error_message) }
    end

    context 'with valid package file' do
      it 'calls the UpdatePackageFromMetadataService' do
        expect_next_instance_of(Packages::Nuget::UpdatePackageFromMetadataService, package_file,
          instance_of(Zip::File)) do |service|
          expect(service).to receive(:execute)
        end

        subject
      end
    end

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

      it_behaves_like 'raises an error', 'invalid package file'
    end

    context 'when linked to a non nuget package' do
      before do
        package_file.package.maven!
      end

      it_behaves_like 'raises an error', 'invalid package file'
    end

    context 'with a 0 byte package file' do
      before do
        allow_next_instance_of(Packages::PackageFileUploader) do |instance|
          allow(instance).to receive(:size).and_return(0)
        end
      end

      it_behaves_like 'raises an error', 'invalid package file'
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true
module Packages
  module Nuget
    class CreateDependencyService < BaseService
      def initialize(package, dependencies = [])
        @package = package
        @dependencies = dependencies
      end

      def execute
        return if @dependencies.empty?

        @package.transaction do
          create_dependency_links
          create_dependency_link_metadata
        end
      end

      private

      def create_dependency_links
        ::Packages::CreateDependencyService
          .new(@package, dependencies_for_create_dependency_service)
          .execute
      end

      def create_dependency_link_metadata
        inserted_links = ::Packages::DependencyLink.preload_dependency
                                                   .for_package(@package)

        return if inserted_links.empty?

        rows = inserted_links.map do |dependency_link|
          raw_dependency = raw_dependency_for(dependency_link.dependency)

          next if raw_dependency[:target_framework].blank?

          {
            dependency_link_id: dependency_link.id,
            target_framework: raw_dependency[:target_framework]
          }
        end

        ::ApplicationRecord.legacy_bulk_insert(::Packages::Nuget::DependencyLinkMetadatum.table_name, rows.compact) # rubocop:disable Gitlab/BulkInsert
      end

      def raw_dependency_for(dependency)
        name = dependency.name
        version = dependency.version_pattern.presence

        @dependencies.find do |raw_dependency|
          raw_dependency[:name] == name && raw_dependency[:version] == version
        end
      end

      def dependencies_for_create_dependency_service
        names_and_versions = @dependencies.to_h do |dependency|
          [dependency[:name], version_or_empty_string(dependency[:version])]
        end

        { 'dependencies' => names_and_versions }
      end

      def version_or_empty_string(version)
        return '' if version.blank?

        version
      end
    end
  end
end

```

Response:
# frozen_string_literal: true
require 'spec_helper'

RSpec.describe Packages::Nuget::CreateDependencyService, feature_category: :package_registry do
  let_it_be(:package, reload: true) { create(:nuget_package) }

  describe '#execute' do
    RSpec.shared_examples 'creating dependencies, links and nuget metadata for' do |expected_dependency_names, dependency_count, dependency_link_count|
      let(:dependencies_with_metadata) { dependencies.select { |dep| dep[:target_framework].present? } }

      it 'creates dependencies, links and nuget metadata' do
        expect { subject }
          .to change { Packages::Dependency.count }.by(dependency_count)
          .and change { Packages::DependencyLink.count }.by(dependency_link_count)
          .and change { Packages::Nuget::DependencyLinkMetadatum.count }.by(dependencies_with_metadata.size)
        expect(expected_dependency_names).to contain_exactly(*dependency_names)
        expect(package.dependency_links.map(&:dependency_type).uniq).to contain_exactly('dependencies')

        dependencies_with_metadata.each do |dependency|
          name = dependency[:name]
          version_pattern = service.send(:version_or_empty_string, dependency[:version])
          metadatum = package.dependency_links.joins(:dependency)
                                              .find_by(packages_dependencies: { name: name, version_pattern: version_pattern })
                                              .nuget_metadatum
          expect(metadatum.target_framework).to eq dependency[:target_framework]
        end
      end
    end

    let_it_be(:dependencies) do
      [
        { name: 'Moqi', version: '2.5.6' },
        { name: 'Castle.Core' },
        { name: 'Test.Dependency', version: '2.3.7', target_framework: '.NETStandard2.0' },
        { name: 'Newtonsoft.Json', version: '12.0.3', target_framework: '.NETStandard2.0' }
      ]
    end

    let(:dependency_names) { package.dependency_links.flat_map(&:dependency).map(&:name) }
    let(:service) { described_class.new(package, dependencies) }

    subject { service.execute }

    it_behaves_like 'creating dependencies, links and nuget metadata for', %w[Castle.Core Moqi Newtonsoft.Json Test.Dependency], 4, 4

    context 'with existing dependencies' do
      let_it_be(:exisiting_dependency) { create(:packages_dependency, name: 'Moqi', version_pattern: '2.5.6') }

      it_behaves_like 'creating dependencies, links and nuget metadata for', %w[Castle.Core Moqi Newtonsoft.Json Test.Dependency], 3, 4
    end

    context 'with dependencies with no target framework' do
      let_it_be(:dependencies) do
        [
          { name: 'Moqi', version: '2.5.6' },
          { name: 'Castle.Core' },
          { name: 'Test.Dependency', version: '2.3.7' },
          { name: 'Newtonsoft.Json', version: '12.0.3' }
        ]
      end

      it_behaves_like 'creating dependencies, links and nuget metadata for', %w[Castle.Core Moqi Newtonsoft.Json Test.Dependency], 4, 4
    end

    context 'with empty dependencies' do
      let_it_be(:dependencies) { [] }

      it 'is a no op' do
        expect(service).not_to receive(:create_dependency_links)
        expect(service).not_to receive(:create_dependency_link_metadata)

        subject
      end
    end
  end
end


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

module Packages
  module Nuget
    module Symbols
      class ExtractSignatureAndChecksumService
        include Gitlab::Utils::StrongMemoize

        # More information about the GUID format can be found here:
        # https://github.com/dotnet/symstore/blob/main/docs/specs/SSQP_Key_Conventions.md#key-formatting-basic-rules
        GUID_START_INDEX = 7
        GUID_END_INDEX = 26
        SIGNATURE_LENGTH = 16
        TWENTY_ZEROED_BYTES = "\u0000" * 20
        GUID_PARTS_LENGTHS = [4, 2, 2, 8].freeze
        GUID_AGE_PART = 'FFFFFFFF'
        TWO_CHARACTER_HEX_REGEX = /\h{2}/
        GUID_CHUNK_SIZE = 256.bytes
        SHA_CHUNK_SIZE = 16.kilobytes

        # The extraction of the signature in this service is based on the following documentation:
        # https://github.com/dotnet/symstore/blob/main/docs/specs/SSQP_Key_Conventions.md#portable-pdb-signature

        def initialize(file)
          @file = file
        end

        def execute
          return error_response unless signature

          ServiceResponse.success(payload: { signature: signature, checksum: checksum })
        end

        private

        attr_reader :file

        def signature
          return unless pdb_id

          # Convert the GUID into an array of two-character hex strings
          guid = pdb_id.first(SIGNATURE_LENGTH).unpack('H*').flat_map { |el| el.scan(TWO_CHARACTER_HEX_REGEX) }

          # Reorder the GUID parts based on arbitrary lengths
          guid = GUID_PARTS_LENGTHS.map { |length| guid.shift(length) }

          # Concatenate the parts of the GUID back together
          result = guid.first(3).map(&:reverse)
          result << guid.last
          result = result.join
          result << GUID_AGE_PART
        end
        strong_memoize_attr :signature

        # https://github.com/dotnet/corefx/blob/master/src/System.Reflection.Metadata/specs/PE-COFF.md#portable-pdb-checksum
        def checksum
          sha = OpenSSL::Digest.new('SHA256')
          count = 0
          chunk = (+'').force_encoding(Encoding::BINARY)
          file.rewind

          while file.read(SHA_CHUNK_SIZE, chunk)
            count += 1
            chunk[pdb_id] = TWENTY_ZEROED_BYTES if count == 1
            sha.update(chunk)
          end

          sha.hexdigest
        end

        def pdb_id
          # The ID is located in the first 256 bytes of the symbol `.pdb` file
          chunk = file.read(GUID_CHUNK_SIZE)
          return unless chunk

          # Find the index of the first occurrence of 'Blob'
          guid_index = chunk.index('Blob')
          return unless guid_index

          # Extract the binary GUID from the symbol content
          chunk[(guid_index + GUID_START_INDEX)..(guid_index + GUID_END_INDEX)]
        end
        strong_memoize_attr :pdb_id

        def error_response
          ServiceResponse.error(message: 'Could not find the signature in the symbol file')
        end
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Packages::Nuget::Symbols::ExtractSignatureAndChecksumService, feature_category: :package_registry do
  let_it_be(:symbol_file_path) { expand_fixture_path('packages/nuget/symbol/package.pdb') }
  let(:symbol_file) { File.new(symbol_file_path) }

  let(:service) { described_class.new(symbol_file) }

  after do
    symbol_file.close
  end

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

    context 'with a valid symbol file' do
      it 'returns the signature and checksum' do
        payload = subject.payload

        expect(payload[:signature]).to eq('b91a152048fc4b3883bf3cf73fbc03f1FFFFFFFF')
        expect(payload[:checksum]).to eq('20151ab9fc48384b83bf3cf73fbc03f1d49166cc356139845f290d1d315256c0')
      end

      it 'reads the file in chunks' do
        expect(symbol_file).to receive(:read).with(described_class::GUID_CHUNK_SIZE).and_call_original
        expect(symbol_file).to receive(:read).with(described_class::SHA_CHUNK_SIZE, instance_of(String))
          .at_least(:once).and_call_original

        subject
      end
    end

    context 'with an invalid symbol file' do
      before do
        allow(symbol_file).to receive(:read).and_return('invalid')
      end

      it 'returns an error' do
        expect(subject).to be_error
        expect(subject.message).to eq('Could not find the signature in the symbol file')
      end
    end
  end
end


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

module Packages
  module Nuget
    module Symbols
      class CreateSymbolFilesService
        ExtractionError = Class.new(StandardError)
        SYMBOL_ENTRIES_LIMIT = 100
        CONTENT_TYPE = 'application/octet-stream'

        def initialize(package, package_zip_file)
          @package = package
          @symbol_entries = package_zip_file.glob('**/*.pdb')
        end

        def execute
          return if symbol_entries.empty?

          process_symbol_entries
        rescue ExtractionError => e
          Gitlab::ErrorTracking.track_exception(e, class: self.class.name, package_id: package.id)
        end

        private

        attr_reader :package, :symbol_entries

        def process_symbol_entries
          Tempfile.create('nuget_extraction_symbol_file') do |tmp_file|
            symbol_entries.each_with_index do |entry, index|
              raise ExtractionError, 'too many symbol entries' if index >= SYMBOL_ENTRIES_LIMIT

              entry.extract(tmp_file.path) { true }
              File.open(tmp_file.path, 'rb') do |file|
                create_symbol(entry.name, file)
              end
            end
          end
        rescue Zip::EntrySizeError => e
          raise ExtractionError, "symbol file has the wrong entry size: #{e.message}"
        rescue Zip::EntryNameError => e
          raise ExtractionError, "symbol file has the wrong entry name: #{e.message}"
        end

        def create_symbol(path, file)
          signature, checksum = extract_signature_and_checksum(file)
          return if signature.blank? || checksum.blank?

          ::Packages::Nuget::Symbol.create!(
            package: package,
            file: { tempfile: file, filename: path.downcase, content_type: CONTENT_TYPE },
            file_path: path,
            signature: signature,
            size: file.size,
            file_sha256: checksum
          )
        rescue StandardError => e
          Gitlab::ErrorTracking.track_exception(e, class: self.class.name, package_id: package.id)
        end

        def extract_signature_and_checksum(file)
          ::Packages::Nuget::Symbols::ExtractSignatureAndChecksumService
            .new(file)
            .execute
            .payload
            .values_at(:signature, :checksum)
        end
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Packages::Nuget::Symbols::CreateSymbolFilesService, feature_category: :package_registry do
  let_it_be(:package) { create(:nuget_package) }
  let_it_be(:package_file) do
    create(:package_file, :snupkg, package: package,
      file_fixture: expand_fixture_path('packages/nuget/package_with_symbols.snupkg'))
  end

  let(:package_zip_file) { Zip::File.new(package_file.file) }
  let(:service) { described_class.new(package, package_zip_file) }

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

    shared_examples 'logging an error' do |error_class|
      it 'logs the error' do
        expect(Gitlab::ErrorTracking).to receive(:track_exception).with(
          an_instance_of(error_class),
          class: described_class.name,
          package_id: package.id
        )

        subject
      end
    end

    context 'when symbol files are found' do
      it 'creates a symbol record and extracts the signature' do
        expect_next_instance_of(Packages::Nuget::Symbols::ExtractSignatureAndChecksumService,
          instance_of(File)) do |service|
          expect(service).to receive(:execute).and_call_original
        end

        expect { subject }.to change { package.nuget_symbols.count }.by(1)
      end
    end

    context 'when symbol files hit the limit' do
      before do
        stub_const("#{described_class}::SYMBOL_ENTRIES_LIMIT", 0)
      end

      it 'does not create a symbol record' do
        expect { subject }.not_to change { package.nuget_symbols.count }
      end

      it_behaves_like 'logging an error', described_class::ExtractionError
    end

    context 'without a signature' do
      before do
        allow_next_instance_of(Packages::Nuget::Symbols::ExtractSignatureAndChecksumService) do |instance|
          allow(instance).to receive(:execute).and_return(ServiceResponse.success(payload: { signature: nil }))
        end
      end

      it 'does not call create! on the symbol record' do
        expect(::Packages::Nuget::Symbol).not_to receive(:create!)

        subject
      end
    end

    context 'without a checksum' do
      before do
        allow_next_instance_of(Packages::Nuget::Symbols::ExtractSignatureAndChecksumService) do |instance|
          allow(instance).to receive(:execute).and_return(ServiceResponse.success(payload: { checksum: nil }))
        end
      end

      it 'does not call create! on the symbol record' do
        expect(::Packages::Nuget::Symbol).not_to receive(:create!)

        subject
      end
    end

    context 'with existing duplicate symbol records' do
      let_it_be(:symbol) { create(:nuget_symbol, package: package) }

      before do
        allow_next_instance_of(Packages::Nuget::Symbols::ExtractSignatureAndChecksumService) do |instance|
          allow(instance).to receive(:execute).and_return(
            ServiceResponse.success(payload: { signature: symbol.signature, checksum: symbol.file_sha256 })
          )
        end
      end

      it 'does not create a symbol record' do
        expect { subject }.not_to change { package.nuget_symbols.count }
      end

      it_behaves_like 'logging an error', ActiveRecord::RecordInvalid
    end

    context 'when a symbol file has the wrong entry size' do
      before do
        allow_next_instance_of(Zip::Entry) do |instance|
          allow(instance).to receive(:extract).and_raise(Zip::EntrySizeError)
        end
      end

      it_behaves_like 'logging an error', described_class::ExtractionError
    end

    context 'when a symbol file has the wrong entry name' do
      before do
        allow_next_instance_of(Zip::Entry) do |instance|
          allow(instance).to receive(:extract).and_raise(Zip::EntryNameError)
        end
      end

      it_behaves_like 'logging an error', described_class::ExtractionError
    end
  end
end


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

module Packages
  module Conan
    class SinglePackageSearchService # rubocop:disable Search/NamespacedClass
      include Gitlab::Utils::StrongMemoize

      def initialize(query, current_user)
        @name, @version, @username, _ = query.split(%r{[@/]})
        @current_user = current_user
      end

      def execute
        ServiceResponse.success(payload: { results: search_results })
      end

      private

      attr_reader :name, :version, :username, :current_user

      def search_results
        return [] unless can_access_project_package?

        [package&.conan_recipe].compact
      end

      def package
        project
          .packages
          .with_name(name)
          .with_version(version)
          .order_created
          .last
      end

      def project
        Project.find_by_full_path(full_path)
      end
      strong_memoize_attr :project

      def full_path
        ::Packages::Conan::Metadatum.full_path_from(package_username: username)
      end

      def can_access_project_package?
        Ability.allowed?(current_user, :read_package, project.try(:packages_policy_subject))
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Packages::Conan::SinglePackageSearchService, feature_category: :package_registry do
  let_it_be(:user) { create(:user) }
  let_it_be(:project) { create(:project, :public) }

  let!(:conan_package) { create(:conan_package, project: project) }
  let!(:conan_package2) { create(:conan_package, project: project) }

  describe '#execute' do
    context 'with a valid query and user with permissions' do
      before do
        allow_next_instance_of(described_class) do |service|
          allow(service).to receive(:can_access_project_package?).and_return(true)
        end
      end

      it 'returns the correct package' do
        [conan_package, conan_package2].each do |package|
          result = described_class.new(package.conan_recipe, user).execute

          expect(result.status).to eq :success
          expect(result[:results]).to match_array([package.conan_recipe])
        end
      end
    end

    context 'with a user without permissions' do
      before do
        allow_next_instance_of(described_class) do |service|
          allow(service).to receive(:can_access_project_package?).and_return(false)
        end
      end

      it 'returns an empty array' do
        result = described_class.new(conan_package.conan_recipe, user).execute

        expect(result.status).to eq :success
        expect(result[:results]).to match_array([])
      end
    end
  end
end


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

module Packages
  module Conan
    class CreatePackageFileService
      attr_reader :package, :file, :params

      def initialize(package, file, params)
        @package = package
        @file = file
        @params = params
      end

      def execute
        package_file = package.package_files.build(
          file: file,
          size: params['file.size'],
          file_name: params[:file_name],
          file_sha1: params['file.sha1'],
          file_md5: params['file.md5'],
          conan_file_metadatum_attributes: {
            recipe_revision: params[:recipe_revision],
            package_revision: params[:package_revision],
            conan_package_reference: params[:conan_package_reference],
            conan_file_type: params[:conan_file_type]
          }
        )

        if params[:build].present?
          package_file.package_file_build_infos << package_file.package_file_build_infos.build(pipeline: params[:build].pipeline)
        end

        package_file.save!
        package_file
      end
    end
  end
end

```

Response:
# frozen_string_literal: true
require 'spec_helper'

RSpec.describe Packages::Conan::CreatePackageFileService, feature_category: :package_registry do
  include WorkhorseHelpers

  let_it_be(:package) { create(:conan_package) }
  let_it_be(:user) { create(:user) }

  describe '#execute' do
    let(:file_name) { 'foo.tgz' }

    subject { described_class.new(package, file, params).execute }

    shared_examples 'a valid package_file' do
      let(:params) do
        {
          file_name: file_name,
          'file.md5': '12345',
          'file.sha1': '54321',
          'file.size': '128',
          'file.type': 'txt',
          recipe_revision: '0',
          package_revision: '0',
          conan_package_reference: '123456789',
          conan_file_type: :package_file
        }.with_indifferent_access
      end

      it 'creates a new package file' do
        package_file = subject

        expect(package_file).to be_valid
        expect(package_file.file_name).to eq(file_name)
        expect(package_file.file_md5).to eq('12345')
        expect(package_file.size).to eq(128)
        expect(package_file.conan_file_metadatum).to be_valid
        expect(package_file.conan_file_metadatum.recipe_revision).to eq('0')
        expect(package_file.conan_file_metadatum.package_revision).to eq('0')
        expect(package_file.conan_file_metadatum.conan_package_reference).to eq('123456789')
        expect(package_file.conan_file_metadatum.conan_file_type).to eq('package_file')
        expect(package_file.file.read).to eq('content')
      end

      it_behaves_like 'assigns build to package file'
    end

    shared_examples 'a valid recipe_file' do
      let(:params) do
        {
          file_name: file_name,
          'file.md5': '12345',
          'file.sha1': '54321',
          'file.size': '128',
          'file.type': 'txt',
          recipe_revision: '0',
          conan_file_type: :recipe_file
        }.with_indifferent_access
      end

      it 'creates a new recipe file' do
        package_file = subject

        expect(package_file).to be_valid
        expect(package_file.file_name).to eq(file_name)
        expect(package_file.file_md5).to eq('12345')
        expect(package_file.size).to eq(128)
        expect(package_file.conan_file_metadatum).to be_valid
        expect(package_file.conan_file_metadatum.recipe_revision).to eq('0')
        expect(package_file.conan_file_metadatum.package_revision).to be_nil
        expect(package_file.conan_file_metadatum.conan_package_reference).to be_nil
        expect(package_file.conan_file_metadatum.conan_file_type).to eq('recipe_file')
        expect(package_file.file.read).to eq('content')
      end

      it_behaves_like 'assigns build to package file'
    end

    context 'with temp file' do
      let!(:file) do
        upload_path = ::Packages::PackageFileUploader.workhorse_local_upload_path
        file_path = upload_path + '/' + file_name

        FileUtils.mkdir_p(upload_path)
        File.write(file_path, 'content')

        UploadedFile.new(file_path, filename: File.basename(file_path))
      end

      before do
        allow_any_instance_of(Packages::PackageFileUploader).to receive(:size).and_return(128)
      end

      it_behaves_like 'a valid package_file'
      it_behaves_like 'a valid recipe_file'
    end

    context 'with remote file' do
      let!(:fog_connection) do
        stub_package_file_object_storage(direct_upload: true)
      end

      before do
        allow_any_instance_of(Packages::PackageFileUploader).to receive(:size).and_return(128)
      end

      let(:tmp_object) do
        fog_connection.directories.new(key: 'packages').files.create( # rubocop:disable Rails/SaveBang
          key: "tmp/uploads/#{file_name}",
          body: 'content'
        )
      end

      let(:file) { fog_to_uploaded_file(tmp_object) }

      it_behaves_like 'a valid package_file'
      it_behaves_like 'a valid recipe_file'
    end

    context 'file is missing' do
      let(:file) { nil }
      let(:params) do
        {
          file_name: file_name,
          recipe_revision: '0',
          conan_file_type: :recipe_file
        }
      end

      it 'raises an error' do
        expect { subject }.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 Conan
    class SearchService < BaseService
      include ActiveRecord::Sanitization::ClassMethods

      WILDCARD = '*'
      RECIPE_SEPARATOR = '@'

      def execute
        ServiceResponse.success(payload: { results: search_results })
      end

      private

      def search_results
        return [] if wildcard_query?

        return search_for_single_package(sanitized_query) if params[:query].include?(RECIPE_SEPARATOR)

        search_packages
      end

      def wildcard_query?
        params[:query] == WILDCARD
      end

      def sanitized_query
        @sanitized_query ||= sanitize_sql_like(params[:query].delete(WILDCARD))
      end

      def search_for_single_package(query)
        ::Packages::Conan::SinglePackageSearchService
          .new(query, current_user)
          .execute[:results]
      end

      def search_packages
        ::Packages::Conan::PackageFinder
          .new(current_user, { query: build_query }, project: project)
          .execute
          .map(&:conan_recipe)
      end

      def build_query
        return "#{sanitized_query}%" if params[:query].end_with?(WILDCARD)

        sanitized_query
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Packages::Conan::SearchService, feature_category: :package_registry do
  let_it_be(:user) { create(:user) }
  let_it_be(:project) { create(:project, :public) }

  let!(:conan_package) { create(:conan_package, project: project) }
  let!(:conan_package2) { create(:conan_package, project: project) }

  subject { described_class.new(project, user, query: query) }

  before do
    project.add_developer(user)
  end

  describe '#execute' do
    context 'with wildcard' do
      let(:partial_name) { conan_package.name.first[0, 3] }
      let(:query) { "#{partial_name}*" }

      it 'makes a wildcard query' do
        result = subject.execute

        expect(result.status).to eq :success
        expect(result.payload).to eq(results: [conan_package2.conan_recipe, conan_package.conan_recipe])
      end
    end

    context 'with only wildcard' do
      let(:query) { '*' }

      it 'returns empty' do
        result = subject.execute

        expect(result.status).to eq :success
        expect(result.payload).to eq(results: [])
      end
    end

    context 'with no wildcard' do
      let(:query) { conan_package.name }

      it 'makes a search using the beginning of the recipe' do
        result = subject.execute

        expect(result.status).to eq :success
        expect(result.payload).to eq(results: [conan_package.conan_recipe])
      end
    end

    context 'with full recipe match' do
      let(:query) { conan_package.conan_recipe }

      it 'makes an exact search' do
        result = subject.execute

        expect(result.status).to eq :success
        expect(result.payload).to eq(results: [conan_package.conan_recipe])
      end
    end

    context 'with malicious query' do
      let(:query) { 'DROP TABLE foo;' }

      it 'returns empty' do
        result = subject.execute

        expect(result.status).to eq :success
        expect(result.payload).to eq(results: [])
      end
    end

    context 'for project' do
      let_it_be(:project2) { create(:project, :public) }
      let(:query) { conan_package.name }
      let!(:conan_package3) { create(:conan_package, name: conan_package.name, project: project2) }

      context 'when passing a project' do
        it 'returns only packages of the given project' do
          result = subject.execute

          expect(result.status).to eq :success
          expect(result[:results]).to match_array([conan_package.conan_recipe])
        end
      end

      context 'when passing a project with nil' do
        it 'returns all packages' do
          result = described_class.new(nil, user, query: query).execute

          expect(result.status).to eq :success
          expect(result[:results]).to eq([conan_package3.conan_recipe, conan_package.conan_recipe])
        end
      end
    end
  end
end


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

module Packages
  module Conan
    class CreatePackageService < ::Packages::CreatePackageService
      def execute
        create_package!(:conan,
          name: params[:package_name],
          version: params[:package_version],
          conan_metadatum_attributes: {
            package_username: params[:package_username],
            package_channel: params[:package_channel]
          }
        )
      end
    end
  end
end

```

Response:
# frozen_string_literal: true
require 'spec_helper'

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

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

  describe '#execute' do
    subject(:package) { service.execute }

    context 'valid params' do
      let(:params) do
        {
          package_name: 'my-pkg',
          package_version: '1.0.0',
          package_username: ::Packages::Conan::Metadatum.package_username_from(full_path: project.full_path),
          package_channel: 'stable'
        }
      end

      it 'creates a new package' do
        expect(package).to be_valid
        expect(package.name).to eq(params[:package_name])
        expect(package.version).to eq(params[:package_version])
        expect(package.package_type).to eq('conan')
        expect(package.conan_metadatum.package_username).to eq(params[:package_username])
        expect(package.conan_metadatum.package_channel).to eq(params[:package_channel])
      end

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

    context 'invalid params' do
      let(:params) do
        {
          package_name: 'my-pkg',
          package_version: '1.0.0',
          package_username: 'foo/bar',
          package_channel: 'stable'
        }
      end

      it 'fails' do
        expect { package }.to raise_exception(ActiveRecord::RecordInvalid)
      end
    end
  end
end


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

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

      def execute
        return error('Version is empty.', 400) if params[:module_version].blank?
        return error('Access Denied', 403) if current_package_exists_elsewhere?
        return error('Package version already exists.', 403) if current_package_version_exists?
        return error('File is too large.', 400) if file_size_exceeded?

        ApplicationRecord.transaction { create_terraform_module_package! }
      end

      private

      def create_terraform_module_package!
        package = create_package!(:terraform_module, name: name, version: params[:module_version])

        ::Packages::CreatePackageFileService.new(package, file_params).execute

        package
      end

      def current_package_exists_elsewhere?
        ::Packages::Package
          .for_projects(project.root_namespace.all_projects.id_not_in(project.id))
          .with_package_type(:terraform_module)
          .with_name(name)
          .not_pending_destruction
          .exists?
      end

      def current_package_version_exists?
        project.packages
          .with_package_type(:terraform_module)
          .with_name(name)
          .with_version(params[:module_version])
          .not_pending_destruction
          .exists?
      end

      def name
        "#{params[:module_name]}/#{params[:module_system]}"
      end
      strong_memoize_attr :name

      def file_name
        "#{params[:module_name]}-#{params[:module_system]}-#{params[:module_version]}.tgz"
      end
      strong_memoize_attr :file_name

      def file_params
        {
          file: params[:file],
          size: params[:file].size,
          file_sha256: params[:file].sha256,
          file_name: file_name,
          build: params[:build]
        }
      end

      def file_size_exceeded?
        project.actual_limits.exceeded?(:generic_packages_max_file_size, params[:file].size)
      end
    end
  end
end

```

Response:
# frozen_string_literal: true
require 'spec_helper'

RSpec.describe Packages::TerraformModule::CreatePackageService, feature_category: :package_registry do
  let_it_be(:namespace) { create(:namespace) }
  let_it_be(:project) { create(:project, namespace: namespace) }
  let_it_be(:user) { create(:user) }
  let_it_be(:sha256) { '440e5e148a25331bbd7991575f7d54933c0ebf6cc735a18ee5066ac1381bb590' }

  let(:overrides) { {} }

  let(:params) do
    {
      module_name: 'foo',
      module_system: 'bar',
      module_version: '1.0.1',
      file: UploadedFile.new(Tempfile.new('test').path, sha256: sha256),
      file_name: 'foo-bar-1.0.1.tgz'
    }.merge(overrides)
  end

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

  describe '#execute' do
    shared_examples 'creating a package' do
      it 'creates a package' do
        expect { subject }
          .to change { ::Packages::Package.count }.by(1)
          .and change { ::Packages::Package.terraform_module.count }.by(1)
      end
    end

    context 'valid package' do
      it_behaves_like 'creating a package'
    end

    context 'package already exists elsewhere' do
      let(:project2) { create(:project, namespace: namespace) }
      let!(:existing_package) { create(:terraform_module_package, project: project2, name: 'foo/bar', version: '1.0.0') }

      it { expect(subject[:http_status]).to eq 403 }
      it { expect(subject[:message]).to be 'Access Denied' }

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

        it_behaves_like 'creating a package'
      end
    end

    context 'version already exists' do
      let!(:existing_version) { create(:terraform_module_package, project: project, name: 'foo/bar', version: '1.0.1') }

      it { expect(subject[:http_status]).to eq 403 }
      it { expect(subject[:message]).to be 'Package version already exists.' }

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

        it_behaves_like 'creating a package'
      end
    end

    context 'with empty version' do
      let(:overrides) { { module_version: '' } }

      it { expect(subject[:http_status]).to eq 400 }
      it { expect(subject[:message]).to eq 'Version is empty.' }
    end
  end
end


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

module Packages
  module Generic
    class CreatePackageFileService < BaseService
      def execute
        ::Packages::Package.transaction do
          create_package_file(find_or_create_package)
        end
      end

      private

      def find_or_create_package
        package_params = {
          name: params[:package_name],
          version: params[:package_version],
          build: params[:build],
          status: params[:status]
        }

        package = ::Packages::Generic::FindOrCreatePackageService
          .new(project, current_user, package_params)
          .execute

        unless Namespace::PackageSetting.duplicates_allowed?(package)
          raise ::Packages::DuplicatePackageError if target_file_is_duplicate?(package)
        end

        package.update_column(:status, params[:status]) if params[:status] && params[:status] != package.status

        package.create_build_infos!(params[:build])

        package
      end

      def create_package_file(package)
        file_params = {
          file: params[:file],
          size: params[:file].size,
          file_sha256: params[:file].sha256,
          file_name: params[:file_name],
          build: params[:build]
        }

        ::Packages::CreatePackageFileService.new(package, file_params).execute
      end

      def target_file_is_duplicate?(package)
        package
          .package_files
          .with_file_name(params[:file_name])
          .not_pending_destruction
          .exists?
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Packages::Generic::CreatePackageFileService, feature_category: :package_registry do
  let_it_be(:project) { create(:project) }
  let_it_be(:user) { create(:user) }
  let_it_be(:pipeline) { create(:ci_pipeline, user: user) }
  let_it_be(:file_name) { 'myfile.tar.gz.1' }

  let(:build) { double('build', pipeline: pipeline) }

  describe '#execute' do
    let_it_be(:package) { create(:generic_package, project: project) }

    let(:sha256) { '440e5e148a25331bbd7991575f7d54933c0ebf6cc735a18ee5066ac1381bb590' }
    let(:temp_file) { Tempfile.new("test") }
    let(:file) { UploadedFile.new(temp_file.path, sha256: sha256) }
    let(:package_service) { double }

    let(:params) do
      {
        package_name: 'mypackage',
        package_version: '0.0.1',
        file: file,
        file_name: file_name,
        build: build
      }
    end

    let(:package_params) do
      {
        name: params[:package_name],
        version: params[:package_version],
        build: params[:build],
        status: nil
      }
    end

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

    before do
      FileUtils.touch(temp_file)
      expect(::Packages::Generic::FindOrCreatePackageService).to receive(:new).with(project, user, package_params).and_return(package_service)
      expect(package_service).to receive(:execute).and_return(package)
    end

    after do
      FileUtils.rm_f(temp_file)
    end

    it 'creates package file', :aggregate_failures do
      expect { execute_service }.to change { package.package_files.count }.by(1)
        .and change { Packages::PackageFileBuildInfo.count }.by(1)

      package_file = package.package_files.last
      aggregate_failures do
        expect(package_file.package.status).to eq('default')
        expect(package_file.package).to eq(package)
        expect(package_file.file_name).to eq(file_name)
        expect(package_file.size).to eq(file.size)
        expect(package_file.file_sha256).to eq(sha256)
      end
    end

    context 'with a status' do
      let(:params) { super().merge(status: 'hidden') }
      let(:package_params) { super().merge(status: 'hidden') }

      it 'updates an existing packages status' do
        expect { execute_service }.to change { package.package_files.count }.by(1)
          .and change { Packages::PackageFileBuildInfo.count }.by(1)

        package_file = package.package_files.last
        aggregate_failures do
          expect(package_file.package.status).to eq('hidden')
        end
      end
    end

    it_behaves_like 'assigns build to package file'

    context 'with existing package' do
      let_it_be(:duplicate_file) { create(:package_file, package: package, file_name: file_name) }

      it { expect { execute_service }.to change { project.package_files.count }.by(1) }

      context 'when duplicates are not allowed' do
        before do
          package.project.namespace.package_settings.update!(generic_duplicates_allowed: false)
        end

        it 'does not allow duplicates' do
          expect { execute_service }.to raise_error(::Packages::DuplicatePackageError)
            .and change { project.package_files.count }.by(0)
        end

        context 'when the file is pending destruction' do
          before do
            duplicate_file.update_column(:status, :pending_destruction)
          end

          it 'allows creating the file' do
            expect { execute_service }.to change { project.package_files.count }.by(1)
          end
        end

        context 'when the package name matches the exception regex' do
          before do
            package.project.namespace.package_settings.update!(generic_duplicate_exception_regex: '.*')
          end

          it { expect { execute_service }.to change { project.package_files.count }.by(1) }
        end
      end

      context 'with multiple files for the same package and the same pipeline' do
        let(:file_2_params) { params.merge(file_name:  'myfile.tar.gz.2', file: file2) }
        let(:file_3_params) { params.merge(file_name:  'myfile.tar.gz.3', file: file3) }

        let(:temp_file2) { Tempfile.new("test2") }
        let(:temp_file3) { Tempfile.new("test3") }

        let(:file2) { UploadedFile.new(temp_file2.path, sha256: sha256) }
        let(:file3) { UploadedFile.new(temp_file3.path, sha256: sha256) }

        before do
          FileUtils.touch(temp_file2)
          FileUtils.touch(temp_file3)
          expect(::Packages::Generic::FindOrCreatePackageService).to receive(:new).with(project, user, package_params).and_return(package_service).twice
          expect(package_service).to receive(:execute).and_return(package).twice
        end

        after do
          FileUtils.rm_f(temp_file2)
          FileUtils.rm_f(temp_file3)
        end

        it 'creates the build info only once' 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 { package.build_infos.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 Generic
    class FindOrCreatePackageService < ::Packages::CreatePackageService
      def execute
        find_or_create_package!(::Packages::Package.package_types['generic'])
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

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

  let(:params) do
    {
      name: 'mypackage',
      version: '0.0.1'
    }
  end

  describe '#execute' do
    context 'when packages does not exist yet' do
      it 'creates package' do
        service = described_class.new(project, user, params)

        expect { service.execute }.to change { project.packages.generic.count }.by(1)

        package = project.packages.generic.last

        aggregate_failures do
          expect(package.creator).to eq(user)
          expect(package.name).to eq('mypackage')
          expect(package.version).to eq('0.0.1')
          expect(package.last_build_info).to be_nil
        end
      end

      it 'creates package and package build info when build is provided' do
        service = described_class.new(project, user, params.merge(build: ci_build))

        expect { service.execute }.to change { project.packages.generic.count }.by(1)

        package = project.packages.generic.last

        aggregate_failures do
          expect(package.creator).to eq(user)
          expect(package.name).to eq('mypackage')
          expect(package.version).to eq('0.0.1')
          expect(package.last_build_info.pipeline).to eq(ci_build.pipeline)
        end
      end
    end

    context 'when packages already exists' do
      let!(:package) { project.packages.generic.create!(params) }

      context 'when package was created manually' do
        it 'finds the package and does not create package build info even if build is provided' do
          service = described_class.new(project, user, params.merge(build: ci_build))

          expect do
            found_package = service.execute

            expect(found_package).to eq(package)
          end.not_to change { project.packages.generic.count }

          expect(package.reload.last_build_info).to be_nil
        end
      end

      context 'when package was created by pipeline' do
        let(:pipeline) { create(:ci_pipeline, project: project) }

        before do
          package.build_infos.create!(pipeline: pipeline)
        end

        it 'finds the package and does not change package build info even if build is provided' do
          service = described_class.new(project, user, params.merge(build: ci_build))

          expect do
            found_package = service.execute

            expect(found_package).to eq(package)
          end.not_to change { project.packages.generic.count }

          expect(package.reload.last_build_info.pipeline).to eq(pipeline)
        end
      end

      context 'when a pending_destruction package exists', :aggregate_failures do
        let!(:package) { project.packages.generic.create!(params.merge(status: :pending_destruction)) }

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

          expect { service.execute }.to change { project.packages.generic.count }.by(1)

          package = project.packages.generic.last

          expect(package.creator).to eq(user)
          expect(package.name).to eq('mypackage')
          expect(package.version).to eq('0.0.1')
          expect(package.last_build_info).to be_nil
        end
      end
    end
  end
end


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

module Packages
  module Rpm
    class ParsePackageService
      include ::Gitlab::Utils::StrongMemoize

      BUILD_ATTRIBUTES_METHOD_NAMES = %i[changelogs requirements provides].freeze
      STATIC_ATTRIBUTES = %i[name version release summary description arch
                             license sourcerpm group buildhost packager vendor].freeze

      CHANGELOGS_RPM_KEYS = %i[changelogtext changelogtime].freeze
      REQUIREMENTS_RPM_KEYS = %i[requirename requireversion requireflags].freeze
      PROVIDES_RPM_KEYS = %i[providename provideflags provideversion].freeze

      def initialize(package_file)
        @rpm = RPM::File.new(package_file)
      end

      def execute
        raise ArgumentError, 'Unable to parse package' unless valid_package?

        {
          files: rpm.files || [],
          epoch: package_tags[:epoch] || '0',
          changelogs: build_changelogs,
          requirements: build_requirements,
          provides: build_provides,
          directories: package_tags[:dirnames]
        }.merge(extract_static_attributes)
      end

      private

      attr_reader :rpm

      def valid_package?
        rpm.files && package_tags && true
      rescue RuntimeError
        # if arr-pm throws an error due to an incorrect file format,
        # we just want this validation to fail rather than throw an exception
        false
      end

      def package_tags
        rpm.tags
      end
      strong_memoize_attr :package_tags

      def extract_static_attributes
        STATIC_ATTRIBUTES.index_with do |attribute|
          package_tags[attribute]
        end
      end

      # Define methods for building RPM attribute data from parsed package
      # Transform
      # changelogtime: [123, 234],
      # changelogname: ["First", "Second"]
      # changelogtext: ["Work1", "Work2"]
      # Into
      # changelog: [
      #   {changelogname: "First", changelogtext: "Work1", changelogtime: 123},
      #   {changelogname: "Second", changelogtext: "Work2", changelogtime: 234}
      # ]
      BUILD_ATTRIBUTES_METHOD_NAMES.each do |resource|
        define_method("build_#{resource}") do
          resource_keys = self.class.const_get("#{resource.upcase}_RPM_KEYS", false).dup
          return [] if resource_keys.any? { package_tags[_1].blank? }

          first_attributes = package_tags[resource_keys.first]
          zipped_data = first_attributes.zip(*resource_keys[1..].map { package_tags[_1] })
          build_hashes(resource_keys, zipped_data)
        end
      end

      def build_hashes(resource_keys, zipped_data)
        zipped_data.map do |data|
          resource_keys.zip(data).to_h
        end
      end
    end
  end
end

```

Response:
# frozen_string_literal: true
require 'spec_helper'

RSpec.describe Packages::Rpm::ParsePackageService, feature_category: :package_registry do
  let(:package_file) { File.open('spec/fixtures/packages/rpm/hello-0.0.1-1.fc29.x86_64.rpm') }

  describe 'dynamic private methods' do
    described_class::BUILD_ATTRIBUTES_METHOD_NAMES.each do |attribute|
      it 'define dynamic build attribute method' do
        expect(described_class).to be_private_method_defined("build_#{attribute}")
      end
    end
  end

  describe '#execute' do
    subject { described_class.new(package_file).execute }

    shared_examples 'valid package parsing' do
      it 'return hash' do
        expect(subject).to be_a(Hash)
      end

      it 'has all static attribute keys' do
        expect(subject.keys).to include(*described_class::STATIC_ATTRIBUTES)
      end

      it 'includes epoch attribute' do
        expect(subject[:epoch]).not_to be_blank
      end

      it 'has all built attributes with array values' do
        result = subject
        described_class::BUILD_ATTRIBUTES_METHOD_NAMES.each do |attribute|
          expect(result).to have_key(attribute)
          expect(result[attribute]).to be_a(Array)
        end
      end
    end

    context 'when wrong format file received' do
      let(:package_file) { File.open('spec/fixtures/rails_sample.jpg') }

      it 'raise error' do
        expect { subject }.to raise_error(ArgumentError)
      end
    end

    context 'when valid file uploaded' do
      context 'when .rpm file uploaded' do
        it_behaves_like 'valid package parsing'
      end

      context 'when .src.rpm file uploaded' do
        let(:package_file) { File.open('spec/fixtures/packages/rpm/hello-0.0.1-1.fc29.src.rpm') }

        it_behaves_like 'valid package parsing'
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true
module Packages
  module Rpm
    module RepositoryMetadata
      class BuildRepomdXmlService
        ROOT_ATTRIBUTES = {
          xmlns: 'http://linux.duke.edu/metadata/repo',
          'xmlns:rpm': 'http://linux.duke.edu/metadata/rpm'
        }.freeze
        ALLOWED_DATA_VALUE_KEYS = %i[checksum open-checksum location timestamp size open-size].freeze

        # Expected `data` structure
        #
        # data = {
        #   filelists: {
        #     checksum: { type: "sha256", value: "123" },
        #     location: { href: "repodata/123-filelists.xml.gz" },
        #     ...
        #   },
        #   ...
        # }
        def initialize(data)
          @data = data
        end

        def execute
          Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
            xml.repomd(ROOT_ATTRIBUTES) do
              xml.revision Time.now.to_i
              build_data_info(xml)
            end
          end.to_xml
        end

        private

        attr_reader :data

        def build_data_info(xml)
          data.each do |filename, info|
            xml.data(type: filename) do
              build_file_info(info, xml)
            end
          end
        end

        def build_file_info(info, xml)
          info.slice(*ALLOWED_DATA_VALUE_KEYS).each do |key, attributes|
            value = attributes.delete(:value)
            xml.method_missing(key, value, attributes)
          end
        end
      end
    end
  end
end

```

Response:
# frozen_string_literal: true
require 'spec_helper'

RSpec.describe Packages::Rpm::RepositoryMetadata::BuildRepomdXmlService, feature_category: :package_registry do
  describe '#execute' do
    subject { described_class.new(data).execute }

    let(:data) do
      {
        filelists: {
          checksum: { type: "sha256", value: "123" },
          'open-checksum': { type: "sha256", value: "123" },
          location: { href: "repodata/123-filelists.xml.gz" },
          timestamp: { value: 1644602784 },
          size: { value: 11111 },
          'open-size': { value: 11111 }
        },
        primary: {
          checksum: { type: "sha256", value: "234" },
          'open-checksum': { type: "sha256", value: "234" },
          location: { href: "repodata/234-primary.xml.gz" },
          timestamp: { value: 1644602784 },
          size: { value: 22222 },
          'open-size': { value: 22222 }
        },
        other: {
          checksum: { type: "sha256", value: "345" },
          'open-checksum': { type: "sha256", value: "345" },
          location: { href: "repodata/345-other.xml.gz" },
          timestamp: { value: 1644602784 },
          size: { value: 33333 },
          'open-size': { value: 33333 }
        }
      }
    end

    let(:creation_timestamp) { 111111 }

    before do
      allow(Time).to receive(:now).and_return(creation_timestamp)
    end

    it 'generate valid xml' do
      # Have one root attribute
      result = Nokogiri::XML::Document.parse(subject)
      expect(result.children.count).to eq(1)

      # Root attribute name is 'repomd'
      root = result.children.first
      expect(root.name).to eq('repomd')

      # Have the same count of 'data' tags as count of keys in 'data'
      expect(result.css('data').count).to eq(data.count)
    end

    it 'has all data info' do
      result = Nokogiri::XML::Document.parse(subject).remove_namespaces!

      data.each do |tag_name, tag_attributes|
        tag_attributes.each_key do |key|
          expect(result.at("//repomd/data[@type=\"#{tag_name}\"]/#{key}")).not_to be_nil
        end
      end
    end

    context 'when data values has unexpected keys' do
      let(:data) do
        {
          filelists: described_class::ALLOWED_DATA_VALUE_KEYS.each_with_object({}) do |key, result|
            result[:"#{key}-wrong"] = { value: 'value' }
          end
        }
      end

      it 'ignores wrong keys' do
        result = Nokogiri::XML::Document.parse(subject).remove_namespaces!

        data.each do |tag_name, tag_attributes|
          tag_attributes.each_key do |key|
            expect(result.at("//repomd/data[@type=\"#{tag_name}\"]/#{key}")).to be_nil
          end
        end
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true
module Packages
  module Rpm
    module RepositoryMetadata
      class BuildOtherXmlService < BuildXmlBaseService
        ROOT_TAG = 'otherdata'
        ROOT_ATTRIBUTES = {
          xmlns: 'http://linux.duke.edu/metadata/other',
          packages: '0'
        }.freeze

        def execute
          super do |xml|
            xml.package(pkgid: data[:pkgid], name: data[:name], arch: data[:arch]) do
              xml.version epoch: data[:epoch], ver: data[:version], rel: data[:release]
              build_changelog_nodes(xml)
            end
          end
        end

        private

        def build_changelog_nodes(xml)
          data[:changelogs].each do |changelog|
            xml.changelog changelog[:changelogtext], date: changelog[:changelogtime]
          end
        end
      end
    end
  end
end

```

Response:
# frozen_string_literal: true
require 'spec_helper'

RSpec.describe Packages::Rpm::RepositoryMetadata::BuildOtherXmlService, feature_category: :package_registry do
  describe '#execute' do
    subject { described_class.new(data).execute }

    include_context 'with rpm package data'

    let(:data) { xml_update_params }
    let(:changelog_xpath) { "//package/changelog" }

    it 'adds all changelog nodes' do
      result = subject

      expect(result.xpath(changelog_xpath).count).to eq(data[:changelogs].count)
    end

    it 'set required date attribute' do
      result = subject

      data[:changelogs].each do |changelog|
        expect(result.at("#{changelog_xpath}[@date=\"#{changelog[:changelogtime]}\"]")).not_to be_nil
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true
module Packages
  module Rpm
    module RepositoryMetadata
      class BuildPrimaryXmlService < BuildXmlBaseService
        ROOT_TAG = 'metadata'
        ROOT_ATTRIBUTES = {
          xmlns: 'http://linux.duke.edu/metadata/common',
          'xmlns:rpm': 'http://linux.duke.edu/metadata/rpm',
          packages: '0'
        }.freeze

        # Nodes that have only text without attributes
        BASE_ATTRIBUTES = %i[name arch summary description url packager].freeze
        FORMAT_NODE_BASE_ATTRIBUTES = %i[license vendor group buildhost sourcerpm].freeze

        def execute
          super do |xml|
            xml.package(type: :rpm, 'xmlns:rpm': 'http://linux.duke.edu/metadata/rpm') do
              build_base_attributes(xml)
              xml.version epoch: data[:epoch], ver: data[:version], rel: data[:release]
              xml.checksum data[:pkgid], type: 'sha256', pkgid: 'YES'
              xml.size package: data[:packagesize], installed: data[:installedsize], archive: data[:archivesize]
              xml.time file: data[:filetime], build: data[:buildtime]
              xml.location href: data[:location] if data[:location].present?
              build_format_node(xml)
            end
          end
        end

        private

        def build_base_attributes(xml)
          BASE_ATTRIBUTES.each do |attribute|
            xml.method_missing(attribute, data[attribute]) if data[attribute].present?
          end
        end

        def build_format_node(xml)
          xml.format do
            build_base_format_attributes(xml)
            build_provides_node(xml)
            build_requires_node(xml)
          end
        end

        def build_base_format_attributes(xml)
          FORMAT_NODE_BASE_ATTRIBUTES.each do |attribute|
            xml[:rpm].method_missing(attribute, data[attribute]) if data[attribute].present?
          end
        end

        def build_requires_node(xml)
          xml[:rpm].requires do
            data[:requirements].each do |requires|
              xml[:rpm].entry(
                name: requires[:requirename],
                flags: requires[:requireflags],
                ver: requires[:requireversion]
              )
            end
          end
        end

        def build_provides_node(xml)
          xml[:rpm].provides do
            data[:provides].each do |provides|
              xml[:rpm].entry(
                name: provides[:providename],
                flags: provides[:provideflags],
                ver: provides[:provideversion])
            end
          end
        end
      end
    end
  end
end

```

Response:
# frozen_string_literal: true
require 'spec_helper'

RSpec.describe Packages::Rpm::RepositoryMetadata::BuildPrimaryXmlService, feature_category: :package_registry do
  describe '#execute' do
    subject { described_class.new(data).execute }

    include_context 'with rpm package data'

    let(:data) { xml_update_params }
    let(:required_text_only_attributes) { %i[description summary arch name] }

    it 'adds node with required_text_only_attributes' do
      result = subject

      required_text_only_attributes.each do |attribute|
        expect(
          result.at("//package/#{attribute}").text
        ).to eq(data[attribute])
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true
module Packages
  module Rpm
    module RepositoryMetadata
      class BuildFilelistXmlService < BuildXmlBaseService
        ROOT_TAG = 'filelists'
        ROOT_ATTRIBUTES = {
          xmlns: 'http://linux.duke.edu/metadata/filelists',
          packages: '0'
        }.freeze

        def execute
          super do |xml|
            xml.package(pkgid: data[:pkgid], name: data[:name], arch: data[:arch]) do
              xml.version epoch: data[:epoch], ver: data[:version], rel: data[:release]
              build_file_nodes(xml)
            end
          end
        end

        private

        def build_file_nodes(xml)
          data[:files].each do |path|
            attributes = dir?(path) ? { type: 'dir' } : {}

            xml.file path, **attributes
          end
        end

        def dir?(path)
          # Add trailing slash to path to check
          # if it exists in directories list
          data[:directories].include? File.join(path, '')
        end
      end
    end
  end
end

```

Response:
# frozen_string_literal: true
require 'spec_helper'

RSpec.describe Packages::Rpm::RepositoryMetadata::BuildFilelistXmlService, feature_category: :package_registry do
  describe '#execute' do
    subject { described_class.new(data).execute }

    include_context 'with rpm package data'

    let(:data) { xml_update_params }
    let(:file_xpath) { "//package/file" }

    it 'adds all file nodes' do
      result = subject

      expect(result.xpath(file_xpath).count).to eq(data[:files].count)
    end

    describe 'setting type attribute' do
      context 'when all files are directories' do
        let(:dirs) do
          3.times.map { generate_directory } # rubocop:disable Performance/TimesMap
        end

        let(:files) do
          5.times.map { FFaker::Filesystem.file_name(dirs.sample) } # rubocop:disable Performance/TimesMap
        end

        let(:data) do
          {
            directories: dirs.map { "#{_1}/" }, # Add trailing slash as in original package
            files: dirs + files
          }
        end

        it 'set dir type attribute for directories only' do
          result = subject

          result.xpath(file_xpath).each do |tag|
            if dirs.include?(tag.content)
              expect(tag.attributes['type']&.value).to eq('dir')
            else
              expect(tag.attributes['type']).to be_nil
            end
          end
        end
      end

      def generate_directory
        FFaker::Lorem.words(3).join('/')
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true
module Packages
  module Rpm
    module RepositoryMetadata
      class UpdateXmlService
        BUILDERS = {
          other: ::Packages::Rpm::RepositoryMetadata::BuildOtherXmlService,
          primary: ::Packages::Rpm::RepositoryMetadata::BuildPrimaryXmlService,
          filelist: ::Packages::Rpm::RepositoryMetadata::BuildFilelistXmlService
        }.freeze

        def initialize(filename:, xml: nil, data: {})
          @builder_class = BUILDERS[filename]
          raise ArgumentError, "Filename must be one of: #{BUILDERS.keys.join(', ')}" if @builder_class.nil?

          @xml = Nokogiri::XML(xml) if xml.present?
          @data = data
          @filename = filename
        end

        def execute
          return build_empty_structure if xml.blank?

          remove_existing_packages
          update_xml_document
          update_package_count
          xml.to_xml
        end

        private

        attr_reader :xml, :data, :builder_class, :filename

        def build_empty_structure
          Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
            xml.method_missing(builder_class::ROOT_TAG, builder_class::ROOT_ATTRIBUTES)
          end.to_xml
        end

        def update_xml_document
          # Add to the root xml element a new package metadata node
          xml.at(builder_class::ROOT_TAG).add_child(builder_class.new(data).execute)
        end

        def update_package_count
          packages_count = xml.css("//#{builder_class::ROOT_TAG}/package").count

          xml.at(builder_class::ROOT_TAG).attributes["packages"].value = packages_count.to_s
        end

        def remove_existing_packages
          case filename
          when :primary
            xml.search("checksum:contains('#{data[:pkgid]}')").each { _1.parent&.remove }
          else
            xml.search("[pkgid='#{data[:pkgid]}']").each(&:remove)
          end
        end
      end
    end
  end
end

```

Response:
# frozen_string_literal: true
require 'spec_helper'

RSpec.describe Packages::Rpm::RepositoryMetadata::UpdateXmlService, feature_category: :package_registry do
  describe '#execute' do
    subject { described_class.new(filename: filename, xml: xml, data: data).execute }

    let(:xml) { nil }
    let(:data) { nil }

    shared_examples 'handling not implemented xml filename' do
      let(:filename) { :not_implemented_yet }
      let(:empty_xml) { '' }

      it 'raise error' do
        expect { subject }.to raise_error(ArgumentError)
      end
    end

    shared_context 'with primary xml file data' do
      let(:filename) { :primary }
      let(:empty_xml) do
        <<~XML
          <?xml version="1.0" encoding="UTF-8"?>
          <metadata xmlns="http://linux.duke.edu/metadata/common" xmlns:rpm="http://linux.duke.edu/metadata/rpm" packages="0"/>
        XML
      end
    end

    shared_context 'with other xml file data' do
      let(:filename) { :other }
      let(:empty_xml) do
        <<~XML
          <?xml version="1.0" encoding="UTF-8"?>
          <otherdata xmlns="http://linux.duke.edu/metadata/other" packages="0"/>
        XML
      end
    end

    shared_context 'with filelist xml file data' do
      let(:filename) { :filelist }
      let(:empty_xml) do
        <<~XML
          <?xml version="1.0" encoding="UTF-8"?>
          <filelists xmlns="http://linux.duke.edu/metadata/filelists" packages="0"/>
        XML
      end
    end

    context 'when building empty xml' do
      shared_examples 'generating empty xml' do
        it 'generate expected xml' do
          expect(subject).to eq(empty_xml)
        end
      end

      it_behaves_like 'handling not implemented xml filename'

      context "for 'primary' xml file" do
        include_context 'with primary xml file data'

        it_behaves_like 'generating empty xml'
      end

      context "for 'other' xml file" do
        include_context 'with other xml file data'

        it_behaves_like 'generating empty xml'
      end

      context "for 'filelist' xml file" do
        include_context 'with filelist xml file data'

        it_behaves_like 'generating empty xml'
      end
    end

    context 'when updating xml file' do
      include_context 'with rpm package data'

      let(:xml) { empty_xml }
      let(:data) { xml_update_params }
      let(:builder_class) { described_class::BUILDERS[filename] }

      shared_examples 'updating rpm xml file' do
        context 'when updating existing xml' do
          shared_examples 'changing root tag attribute' do
            it "increment previous 'packages' value by 1" do
              previous_value = Nokogiri::XML(xml).at(builder_class::ROOT_TAG).attributes["packages"].value.to_i
              new_value = Nokogiri::XML(subject).at(builder_class::ROOT_TAG).attributes["packages"].value.to_i

              expect(previous_value + 1).to eq(new_value)
            end
          end

          it 'generate valid xml add expected xml node to existing xml' do
            # Have one root attribute
            result = Nokogiri::XML::Document.parse(subject).remove_namespaces!
            expect(result.children.count).to eq(1)

            # Root node has 1 child with generated node
            expect(result.xpath("//#{builder_class::ROOT_TAG}/package").count).to eq(1)
          end

          context 'when empty xml' do
            it_behaves_like 'changing root tag attribute'
          end

          context 'when xml has children' do
            context "when node with given 'pkgid' does not exist yet" do
              let(:uniq_node_data) do
                xml_update_params.tap do |data|
                  data[:pkgid] = SecureRandom.uuid
                end
              end

              let(:xml) { build_xml_from(uniq_node_data) }

              it 'has children nodes' do
                existing_xml = Nokogiri::XML::Document.parse(xml).remove_namespaces!
                expect(existing_xml.xpath('//package').count).to eq(1)
              end

              it_behaves_like 'changing root tag attribute'
            end

            context "when node with given 'pkgid' already exist" do
              let(:existing_node_data) do
                existing_data = data.dup
                existing_data[:name] = FFaker::Lorem.word
                existing_data
              end

              let(:xml) { build_xml_from(existing_node_data) }

              it 'has children nodes' do
                existing_xml = Nokogiri::XML::Document.parse(xml).remove_namespaces!
                expect(existing_xml.xpath('//package').count).to eq(1)
              end

              it 'replace existing node with new data' do
                existing_xml = Nokogiri::XML::Document.parse(xml).remove_namespaces!
                result = Nokogiri::XML::Document.parse(subject).remove_namespaces!
                expect(result.xpath('//package').count).to eq(1)
                expect(result.xpath('//package').first.to_xml).not_to eq(existing_xml.xpath('//package').first.to_xml)
              end
            end

            def build_xml_from(data)
              described_class.new(filename: filename, xml: empty_xml, data: data).execute
            end
          end
        end
      end

      it_behaves_like 'handling not implemented xml filename'

      context "for 'primary' xml file" do
        include_context 'with primary xml file data'

        it_behaves_like 'updating rpm xml file'
      end

      context "for 'other' xml file" do
        include_context 'with other xml file data'

        it_behaves_like 'updating rpm xml file'
      end

      context "for 'filelist' xml file" do
        include_context 'with filelist xml file data'

        it_behaves_like 'updating rpm xml file'
      end
    end
  end
end