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

module Labels
  class UpdateService < Labels::BaseService
    def initialize(params = {})
      @params = params.to_h.dup.with_indifferent_access
    end

    # returns the updated label
    def execute(label)
      params[:name] = params.delete(:new_name) if params.key?(:new_name)
      params[:color] = convert_color_name_to_hex if params[:color].present?
      params.delete(:lock_on_merge) unless allow_lock_on_merge?(label)

      label.update(params)
      label
    end

    private

    def allow_lock_on_merge?(label)
      return if label.template?
      return unless label.respond_to?(:parent_container)
      return unless label.parent_container.supports_lock_on_merge?

      # If we've made it here, then we're allowed to turn it on. However, we do _not_
      # want to allow it to be turned off. So if it's already set, then don't allow the possibility
      # that it could be turned off.
      !label.lock_on_merge
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Labels::UpdateService, feature_category: :team_planning do
  describe '#execute' do
    let(:project) { create(:project) }

    let(:hex_color) { '#FF0000' }
    let(:named_color) { 'red' }
    let(:upcase_color) { 'RED' }
    let(:spaced_color) { ' red ' }
    let(:unknown_color) { 'unknown' }
    let(:no_color) { '' }

    let(:expected_saved_color) { ::Gitlab::Color.of(hex_color) }

    before do
      @label = Labels::CreateService.new(title: 'Initial', color: '#000000').execute(project: project)
      expect(@label).to be_persisted
    end

    context 'with color in hex-code' do
      it 'updates the label' do
        label = described_class.new(params_with(hex_color)).execute(@label)

        expect(label).to be_valid
        expect(label.reload.color).to eq expected_saved_color
      end
    end

    context 'with color in allowed name' do
      it 'updates the label' do
        label = described_class.new(params_with(named_color)).execute(@label)

        expect(label).to be_valid
        expect(label.reload.color).to eq expected_saved_color
      end
    end

    context 'with color in up-case allowed name' do
      it 'updates the label' do
        label = described_class.new(params_with(upcase_color)).execute(@label)

        expect(label).to be_valid
        expect(label.reload.color).to eq expected_saved_color
      end
    end

    context 'with color surrounded by spaces' do
      it 'updates the label' do
        label = described_class.new(params_with(spaced_color)).execute(@label)

        expect(label).to be_valid
        expect(label.reload.color).to eq expected_saved_color
      end
    end

    context 'with unknown color' do
      it 'doesn\'t update the label' do
        label = described_class.new(params_with(unknown_color)).execute(@label)

        expect(label).not_to be_valid
      end
    end

    context 'with no color' do
      it 'doesn\'t update the label' do
        label = described_class.new(params_with(no_color)).execute(@label)

        expect(label).not_to be_valid
      end
    end

    describe 'lock_on_merge' do
      let_it_be(:params) { { lock_on_merge: true } }

      context 'when feature flag is disabled' do
        before do
          stub_feature_flags(enforce_locked_labels_on_merge: false)
        end

        it 'does not allow setting lock_on_merge' do
          label = described_class.new(params).execute(@label)

          expect(label.reload.lock_on_merge).to be_falsey

          template_label = Labels::CreateService.new(title: 'Initial').execute(template: true)
          label = described_class.new(params).execute(template_label)

          expect(label.reload.lock_on_merge).to be_falsey
        end
      end

      context 'when feature flag is enabled' do
        it 'allows setting lock_on_merge' do
          label = described_class.new(params).execute(@label)

          expect(label.reload.lock_on_merge).to be_truthy
        end

        it 'does not allow lock_on_merge to be unset' do
          label_locked = Labels::CreateService.new(title: 'Initial', lock_on_merge: true).execute(project: project)
          label = described_class.new(title: 'test', lock_on_merge: false).execute(label_locked)

          expect(label.reload.lock_on_merge).to be_truthy
          expect(label.reload.title).to eq 'test'
        end

        it 'does not allow setting lock_on_merge for templates' do
          template_label = Labels::CreateService.new(title: 'Initial').execute(template: true)
          label = described_class.new(params).execute(template_label)

          expect(label.reload.lock_on_merge).to be_falsey
        end
      end
    end
  end

  def params_with(color)
    {
      title: 'A Label',
      color: color
    }
  end
end


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

module Labels
  class CreateService < Labels::BaseService
    def initialize(params = {})
      @params = params.to_h.dup.with_indifferent_access
    end

    # returns the created label
    def execute(target_params)
      params[:color] = convert_color_name_to_hex if params[:color].present?

      project_or_group = target_params[:project] || target_params[:group]

      if project_or_group.present?
        params.delete(:lock_on_merge) unless project_or_group.supports_lock_on_merge?

        project_or_group.labels.create(params)
      elsif target_params[:template]
        label = Label.new(params)
        label.template = true
        label.save
        label
      else
        Gitlab::AppLogger.warn("target_params should contain :project or :group or :template, actual value: #{target_params}")
      end
    end
  end
end

Labels::CreateService.prepend_mod_with('Labels::CreateService')

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Labels::CreateService, feature_category: :team_planning do
  describe '#execute' do
    let(:project) { create(:project) }
    let(:group)   { create(:group) }

    let(:hex_color) { '#FF0000' }
    let(:named_color) { 'red' }
    let(:upcase_color) { 'RED' }
    let(:spaced_color) { ' red ' }
    let(:unknown_color) { 'unknown' }
    let(:no_color) { '' }

    let(:expected_saved_color) { ::Gitlab::Color.of(hex_color) }

    context 'in a project' do
      context 'with color in hex-code' do
        it 'creates a label' do
          label = described_class.new(params_with(hex_color)).execute(project: project)

          expect(label).to be_persisted
          expect(label.color).to eq expected_saved_color
        end
      end

      context 'with color in allowed name' do
        it 'creates a label' do
          label = described_class.new(params_with(named_color)).execute(project: project)

          expect(label).to be_persisted
          expect(label.color).to eq expected_saved_color
        end
      end

      context 'with color in up-case allowed name' do
        it 'creates a label' do
          label = described_class.new(params_with(upcase_color)).execute(project: project)

          expect(label).to be_persisted
          expect(label.color).to eq expected_saved_color
        end
      end

      context 'with color surrounded by spaces' do
        it 'creates a label' do
          label = described_class.new(params_with(spaced_color)).execute(project: project)
          expect(label).to be_persisted
          expect(label.color).to eq expected_saved_color
        end
      end

      context 'with unknown color' do
        it 'doesn\'t create a label' do
          label = described_class.new(params_with(unknown_color)).execute(project: project)

          expect(label).not_to be_persisted
        end
      end

      context 'with no color' do
        it 'doesn\'t create a label' do
          label = described_class.new(params_with(no_color)).execute(project: project)

          expect(label).not_to be_persisted
        end
      end
    end

    context 'in a group' do
      context 'with color in hex-code' do
        it 'creates a label' do
          label = described_class.new(params_with(hex_color)).execute(group: group)

          expect(label).to be_persisted
          expect(label.color).to eq expected_saved_color
        end
      end

      context 'with color in allowed name' do
        it 'creates a label' do
          label = described_class.new(params_with(named_color)).execute(group: group)

          expect(label).to be_persisted
          expect(label.color).to eq expected_saved_color
        end
      end

      context 'with color in up-case allowed name' do
        it 'creates a label' do
          label = described_class.new(params_with(upcase_color)).execute(group: group)

          expect(label).to be_persisted
          expect(label.color).to eq expected_saved_color
        end
      end

      context 'with color surrounded by spaces' do
        it 'creates a label' do
          label = described_class.new(params_with(spaced_color)).execute(group: group)

          expect(label).to be_persisted
          expect(label.color).to eq expected_saved_color
        end
      end

      context 'with unknown color' do
        it 'doesn\'t create a label' do
          label = described_class.new(params_with(unknown_color)).execute(group: group)

          expect(label).not_to be_persisted
        end
      end

      context 'with no color' do
        it 'doesn\'t create a label' do
          label = described_class.new(params_with(no_color)).execute(group: group)

          expect(label).not_to be_persisted
        end
      end
    end

    context 'in admin area' do
      context 'with color in hex-code' do
        it 'creates a label' do
          label = described_class.new(params_with(hex_color)).execute(template: true)

          expect(label).to be_persisted
          expect(label.color).to eq expected_saved_color
        end
      end

      context 'with color in allowed name' do
        it 'creates a label' do
          label = described_class.new(params_with(named_color)).execute(template: true)

          expect(label).to be_persisted
          expect(label.color).to eq expected_saved_color
        end
      end

      context 'with color in up-case allowed name' do
        it 'creates a label' do
          label = described_class.new(params_with(upcase_color)).execute(template: true)

          expect(label).to be_persisted
          expect(label.color).to eq expected_saved_color
        end
      end

      context 'with color surrounded by spaces' do
        it 'creates a label' do
          label = described_class.new(params_with(spaced_color)).execute(template: true)

          expect(label).to be_persisted
          expect(label.color).to eq expected_saved_color
        end
      end

      context 'with unknown color' do
        it 'doesn\'t create a label' do
          label = described_class.new(params_with(unknown_color)).execute(template: true)

          expect(label).not_to be_persisted
        end
      end

      context 'with no color' do
        it 'doesn\'t create a label' do
          label = described_class.new(params_with(no_color)).execute(template: true)

          expect(label).not_to be_persisted
        end
      end
    end

    describe 'lock_on_merge' do
      let_it_be(:params) { { title: 'Locked label', lock_on_merge: true } }

      context 'when feature flag is disabled' do
        before do
          stub_feature_flags(enforce_locked_labels_on_merge: false)
        end

        it 'does not allow setting lock_on_merge' do
          label = described_class.new(params).execute(project: project)
          label2 = described_class.new(params).execute(group: group)
          label3 = described_class.new(params).execute(template: true)

          expect(label.lock_on_merge).to be_falsey
          expect(label2.lock_on_merge).to be_falsey
          expect(label3).not_to be_persisted
        end
      end

      context 'when feature flag is enabled' do
        it 'allows setting lock_on_merge' do
          label = described_class.new(params).execute(project: project)
          label2 = described_class.new(params).execute(group: group)

          expect(label.lock_on_merge).to be_truthy
          expect(label2.lock_on_merge).to be_truthy
        end

        it 'does not alow setting lock_on_merge for templates' do
          label = described_class.new(params).execute(template: true)

          expect(label).not_to be_persisted
        end
      end
    end
  end

  def params_with(color)
    {
      title: 'A Label',
      color: color
    }
  end
end


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

module IssueEmailParticipants
  class CreateService < ::BaseProjectService
    MAX_NUMBER_OF_EMAILS = 6

    attr_reader :target, :emails

    def initialize(target:, current_user:, emails:)
      super(project: target.project, current_user: current_user)

      @target = target
      @emails = emails
    end

    def execute
      return error_feature_flag unless Feature.enabled?(:issue_email_participants, target.project)
      return error_underprivileged unless current_user.can?(:"admin_#{target.to_ability_name}", target)
      return error_no_participants unless emails.present?

      added_emails = add_participants(deduplicate_and_limit_emails)

      if added_emails.any?
        message = add_system_note(added_emails)
        ServiceResponse.success(message: message.upcase_first << ".")
      else
        error_no_participants
      end
    end

    private

    def deduplicate_and_limit_emails
      existing_emails = target.email_participants_emails_downcase
      # Compare downcase versions, but use the original email
      emails.index_by { |email| [email.downcase, email] }.excluding(*existing_emails).each_value
        .first(MAX_NUMBER_OF_EMAILS)
    end

    def add_participants(emails_to_add)
      added_emails = []
      emails_to_add.each do |email|
        new_participant = target.issue_email_participants.create(email: email)
        added_emails << email if new_participant.persisted?
      end

      added_emails
    end

    def add_system_note(added_emails)
      message = format(_("added %{emails}"), emails: added_emails.to_sentence)
      ::SystemNoteService.add_email_participants(target, project, current_user, message)

      message
    end

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

    def error_feature_flag
      # Don't translate feature flag error because it's temporary.
      error("Feature flag issue_email_participants is not enabled for this project.")
    end

    def error_underprivileged
      error(_("You don't have permission to add email participants."))
    end

    def error_no_participants
      error(_("No email participants were added. Either none were provided, or they already exist."))
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe IssueEmailParticipants::CreateService, feature_category: :service_desk do
  shared_examples 'a successful service execution' do
    it 'creates new participants', :aggregate_failures do
      expect(response).to be_success

      issue.reset
      note = issue.notes.last
      expect(note.system?).to be true
      expect(note.author).to eq(user)

      participants_emails = issue.email_participants_emails_downcase

      expected_emails.each do |email|
        expect(participants_emails).to include(email)
        expect(response.message).to include(email)
        expect(note.note).to include(email)
      end
    end
  end

  shared_examples 'a failed service execution' do
    it 'returns error ServiceResponse with message', :aggregate_failures do
      expect(response).to be_error
      expect(response.message).to eq(error_message)
    end
  end

  describe '#execute' do
    let_it_be_with_reload(:project) { create(:project) }
    let_it_be(:user) { create(:user) }
    let_it_be(:issue) { create(:issue, project: project) }

    let(:emails) { nil }
    let(:service) { described_class.new(target: issue, current_user: user, emails: emails) }
    let(:expected_emails) { emails }

    let(:error_feature_flag) { "Feature flag issue_email_participants is not enabled for this project." }
    let(:error_underprivileged) { _("You don't have permission to add email participants.") }
    let(:error_no_participants) do
      _("No email participants were added. Either none were provided, or they already exist.")
    end

    subject(:response) { service.execute }

    context 'when the user is not a project member' do
      let(:error_message) { error_underprivileged }

      it_behaves_like 'a failed service execution'
    end

    context 'when user has reporter role in project' do
      before_all do
        project.add_reporter(user)
      end

      context 'when no emails are provided' do
        let(:error_message) { error_no_participants }

        it_behaves_like 'a failed service execution'
      end

      context 'when one email is provided' do
        let(:emails) { ['user@example.com'] }

        it_behaves_like 'a successful service execution'

        context 'when email is already a participant of the issue' do
          let(:error_message) { error_no_participants }

          before do
            issue.issue_email_participants.create!(email: emails.first)
          end

          it_behaves_like 'a failed service execution'

          context 'when email is formatted in a different case' do
            let(:emails) { ['USER@example.com'] }

            it_behaves_like 'a failed service execution'
          end
        end
      end

      context 'when multiple emails are provided' do
        let(:emails) { ['user@example.com', 'user2@example.com'] }

        it_behaves_like 'a successful service execution'

        context 'when duplicate email provided' do
          let(:emails) { ['user@example.com', 'user@example.com'] }
          let(:expected_emails) { emails[...-1] }

          it_behaves_like 'a successful service execution'
        end

        context 'when an email is already a participant of the issue' do
          let(:expected_emails) { emails[1...] }

          before do
            issue.issue_email_participants.create!(email: emails.first)
          end

          it_behaves_like 'a successful service execution'
        end
      end

      context 'when more than the allowed number of emails a re provided' do
        let(:emails) { (1..7).map { |i| "user#{i}@example.com" } }

        let(:expected_emails) { emails[...-1] }

        it_behaves_like 'a successful service execution'
      end
    end

    context 'when feature flag issue_email_participants is disabled' do
      let(:error_message) { error_feature_flag }

      before do
        stub_feature_flags(issue_email_participants: false)
      end

      it_behaves_like 'a failed service execution'
    end
  end
end


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

module DeployKeys
  class CreateService < Keys::BaseService
    def execute(project: nil)
      DeployKey.create(params.merge(user: user))
    end
  end
end

DeployKeys::CreateService.prepend_mod_with('DeployKeys::CreateService')

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe DeployKeys::CreateService, feature_category: :continuous_delivery do
  let(:user) { create(:user) }
  let(:params) { attributes_for(:deploy_key) }

  subject { described_class.new(user, params) }

  it "creates a deploy key" do
    expect { subject.execute }.to change { DeployKey.where(params.merge(user: user)).count }.by(1)
  end
end


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

module Uploads
  class DestroyService < BaseService
    attr_accessor :model, :current_user

    def initialize(model, user = nil)
      @model = model
      @current_user = user
    end

    def execute(secret, filename)
      upload = find_upload(secret, filename)

      unless current_user && upload && current_user.can?(:destroy_upload, upload)
        return error(_("The resource that you are attempting to access does not "\
                       "exist or you don't have permission to perform this action."))
      end

      if upload.destroy
        success(upload: upload)
      else
        error(_('Upload could not be deleted.'))
      end
    end

    private

    # rubocop: disable CodeReuse/ActiveRecord
    def find_upload(secret, filename)
      uploader = uploader_class.new(model, secret: secret)
      upload_paths = uploader.upload_paths(filename)

      Upload.find_by(model: model, uploader: uploader_class.to_s, path: upload_paths)
    rescue FileUploader::InvalidSecret
      nil
    end
    # rubocop: enable CodeReuse/ActiveRecord

    def uploader_class
      case model
      when Group
        NamespaceFileUploader
      when Project
        FileUploader
      else
        raise ArgumentError, "unknown uploader for #{model.class.name}"
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Uploads::DestroyService, feature_category: :shared do
  let_it_be(:project) { create(:project) }
  let_it_be(:user) { create(:user) }
  let_it_be_with_reload(:upload) { create(:upload, :issuable_upload, model: project) }

  let(:filename) { File.basename(upload.path) }
  let(:secret) { upload.secret }
  let(:model) { project }
  let(:service) { described_class.new(model, user) }

  describe '#execute' do
    subject { service.execute(secret, filename) }

    shared_examples_for 'upload not found' do
      it 'does not delete any upload' do
        expect { subject }.not_to change { Upload.count }
      end

      it 'returns an error' do
        expect(subject[:status]).to eq(:error)
        expect(subject[:message]).to eq("The resource that you are attempting to access does not "\
                                        "exist or you don't have permission to perform this action.")
      end
    end

    context 'when user is nil' do
      let(:user) { nil }

      it_behaves_like 'upload not found'
    end

    context 'when user cannot destroy upload' do
      before do
        project.add_developer(user)
      end

      it_behaves_like 'upload not found'
    end

    context 'when user can destroy upload' do
      before do
        project.add_maintainer(user)
      end

      it 'deletes the upload' do
        expect { subject }.to change { Upload.count }.by(-1)
      end

      it 'returns success response' do
        expect(subject[:status]).to eq(:success)
        expect(subject[:upload]).to eq(upload)
      end

      context 'when upload is not found' do
        let(:filename) { 'not existing filename' }

        it_behaves_like 'upload not found'
      end

      context 'when upload secret is not found' do
        let(:secret) { 'aaaaaaaaaa' }

        it_behaves_like 'upload not found'
      end

      context 'when upload secret has invalid format' do
        let(:secret) { 'invalid' }

        it_behaves_like 'upload not found'
      end

      context 'when unknown model is used' do
        let(:model) { user }

        it 'raises an error' do
          expect { subject }.to raise_exception(ArgumentError)
        end
      end

      context 'when upload belongs to other model' do
        let_it_be(:upload) { create(:upload, :namespace_upload) }

        it_behaves_like 'upload not found'
      end

      context 'when upload destroy fails' do
        before do
          allow(service).to receive(:find_upload).and_return(upload)
          allow(upload).to receive(:destroy).and_return(false)
        end

        it 'returns error' do
          expect(subject[:status]).to eq(:error)
          expect(subject[:message]).to eq('Upload could not be deleted.')
        end
      end
    end
  end
end


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

module ResourceAccessTokens
  class RevokeService < BaseService
    include Gitlab::Utils::StrongMemoize

    RevokeAccessTokenError = Class.new(RuntimeError)

    def initialize(current_user, resource, access_token)
      @current_user = current_user
      @access_token = access_token
      @bot_user = access_token.user
      @resource = resource
    end

    def execute
      return error("#{current_user.name} cannot delete #{bot_user.name}") unless can_destroy_token?
      return error("Failed to find bot user") unless find_member

      access_token.revoke!

      destroy_bot_user

      log_event

      success("Access token #{access_token.name} has been revoked and the bot user has been scheduled for deletion.")
    rescue StandardError => error
      log_error("Failed to revoke access token for #{bot_user.name}: #{error.message}")
      error(error.message)
    end

    private

    attr_reader :current_user, :access_token, :bot_user, :resource

    def destroy_bot_user
      DeleteUserWorker.perform_async(current_user.id, bot_user.id, skip_authorization: true)
    end

    def can_destroy_token?
      %w[project group].include?(resource.class.name.downcase) && can?(current_user, :destroy_resource_access_tokens, resource)
    end

    def find_member
      strong_memoize(:member) do
        next false unless resource.is_a?(Project) || resource.is_a?(Group)

        resource.member(bot_user)
      end
    end

    def log_event
      ::Gitlab::AppLogger.info "PROJECT ACCESS TOKEN REVOCATION: revoked_by: #{current_user.username}, project_id: #{resource.id}, token_user: #{access_token.user.name}, token_id: #{access_token.id}"
    end

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

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

ResourceAccessTokens::RevokeService.prepend_mod_with('ResourceAccessTokens::RevokeService')

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe ResourceAccessTokens::RevokeService, feature_category: :system_access do
  subject { described_class.new(user, resource, access_token).execute }

  let_it_be(:user) { create(:user) }
  let_it_be(:user_non_priviledged) { create(:user) }
  let_it_be(:resource_bot) { create(:user, :project_bot) }

  let(:access_token) { create(:personal_access_token, user: resource_bot) }

  describe '#execute', :sidekiq_inline do
    shared_examples 'revokes access token' do
      it { expect(subject.success?).to be true }

      it { expect(subject.message).to eq("Access token #{access_token.name} has been revoked and the bot user has been scheduled for deletion.") }

      it 'calls delete user worker' do
        expect(DeleteUserWorker).to receive(:perform_async).with(user.id, resource_bot.id, skip_authorization: true)

        subject
      end

      it 'removes membership of bot user' do
        subject

        expect(resource.reload.users).not_to include(resource_bot)
      end

      it 'initiates user removal' do
        subject

        expect(
          Users::GhostUserMigration.where(user: resource_bot, initiator_user: user)
        ).to be_exists
      end

      it 'logs the event' do
        allow(Gitlab::AppLogger).to receive(:info)

        subject

        expect(Gitlab::AppLogger).to have_received(:info).with("PROJECT ACCESS TOKEN REVOCATION: revoked_by: #{user.username}, project_id: #{resource.id}, token_user: #{resource_bot.name}, token_id: #{access_token.id}")
      end
    end

    shared_examples 'rollback revoke steps' do
      it 'does not revoke the access token' do
        subject

        expect(access_token.reload.revoked?).to be false
      end

      it 'does not remove bot from member list' do
        subject

        expect(resource.reload.users).to include(resource_bot)
      end

      it 'does not transfer issuables of bot user to ghost user' do
        issue = create(:issue, author: resource_bot)

        subject

        expect(issue.reload.author.ghost?).to be false
      end

      it 'does not destroy project bot user' do
        subject

        expect(User.exists?(resource_bot.id)).to be_truthy
      end
    end

    shared_examples 'revoke fails' do |resource_type|
      let_it_be(:other_user) { create(:user) }

      context "when access token does not belong to this #{resource_type}" do
        it 'does not find the bot' do
          other_access_token = create(:personal_access_token, user: other_user)

          response = described_class.new(user, resource, other_access_token).execute

          expect(response.success?).to be false
          expect(response.message).to eq("Failed to find bot user")
          expect(access_token.reload.revoked?).to be false
        end
      end

      context 'when user does not have permission to destroy bot' do
        context "when non-#{resource_type} member tries to delete project bot" do
          it 'does not allow other user to delete bot' do
            response = described_class.new(other_user, resource, access_token).execute

            expect(response.success?).to be false
            expect(response.message).to eq("#{other_user.name} cannot delete #{access_token.user.name}")
            expect(access_token.reload.revoked?).to be false
          end
        end

        context "when non-priviledged #{resource_type} member tries to delete project bot" do
          it 'does not allow developer to delete bot' do
            response = described_class.new(user_non_priviledged, resource, access_token).execute

            expect(response.success?).to be false
            expect(response.message).to eq("#{user_non_priviledged.name} cannot delete #{access_token.user.name}")
            expect(access_token.reload.revoked?).to be false
          end
        end
      end

      context 'when deletion of bot user fails' do
        before do
          allow_next_instance_of(::ResourceAccessTokens::RevokeService) do |service|
            allow(service).to receive(:execute).and_return(false)
          end
        end

        it_behaves_like 'rollback revoke steps'
      end
    end

    context 'when resource is a project' do
      let_it_be(:resource) { create(:project, :private) }

      before do
        resource.add_maintainer(user)
        resource.add_developer(user_non_priviledged)
        resource.add_maintainer(resource_bot)
      end

      it_behaves_like 'revokes access token'

      it_behaves_like 'revoke fails', 'project'
    end

    context 'when resource is a group' do
      let_it_be(:resource) { create(:group, :private) }

      before do
        resource.add_owner(user)
        resource.add_maintainer(user_non_priviledged)
        resource.add_maintainer(resource_bot)
      end

      it_behaves_like 'revokes access token'

      it_behaves_like 'revoke fails', 'group'
    end
  end
end


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

module ResourceAccessTokens
  class CreateService < BaseService
    include Gitlab::Utils::StrongMemoize

    def initialize(current_user, resource, params = {})
      @resource_type = resource.class.name.downcase
      @resource = resource
      @current_user = current_user
      @params = params.dup
    end

    def execute
      return error("User does not have permission to create #{resource_type} access token") unless has_permission_to_create?

      access_level = params[:access_level] || Gitlab::Access::MAINTAINER
      return error("Could not provision owner access to project access token") if do_not_allow_owner_access_level_for_project_bot?(access_level)

      return error("Access level of the token can't be greater the access level of the user who created the token") unless validate_access_level(access_level)

      return error(s_('AccessTokens|Access token limit reached')) if reached_access_token_limit?

      user = create_user

      return error(user.errors.full_messages.to_sentence) unless user.persisted?

      user.update!(external: true) if current_user.external?

      member = create_membership(resource, user, access_level)

      unless member.persisted?
        delete_failed_user(user)
        return error("Could not provision #{Gitlab::Access.human_access(access_level.to_i).downcase} access to the access token. ERROR: #{member.errors.full_messages.to_sentence}")
      end

      token_response = create_personal_access_token(user)

      if token_response.success?
        log_event(token_response.payload[:personal_access_token])
        success(token_response.payload[:personal_access_token])
      else
        delete_failed_user(user)
        error(token_response.message)
      end
    end

    private

    attr_reader :resource_type, :resource

    def reached_access_token_limit?
      false
    end

    def username_and_email_generator
      Gitlab::Utils::UsernameAndEmailGenerator.new(
        username_prefix: "#{resource_type}_#{resource.id}_bot",
        email_domain: "noreply.#{Gitlab.config.gitlab.host}"
      )
    end
    strong_memoize_attr :username_and_email_generator

    def has_permission_to_create?
      %w[project group].include?(resource_type) && can?(current_user, :create_resource_access_tokens, resource)
    end

    def create_user
      # Even project maintainers/owners can create project access tokens, which in turn
      # creates a bot user, and so it becomes necessary to  have `skip_authorization: true`
      # since someone like a project maintainer/owner does not inherently have the ability
      # to create a new user in the system.

      ::Users::AuthorizedCreateService.new(current_user, default_user_params).execute
    end

    def delete_failed_user(user)
      DeleteUserWorker.perform_async(current_user.id, user.id, hard_delete: true, skip_authorization: true)
    end

    def default_user_params
      {
        name: params[:name] || "#{resource.name.to_s.humanize} bot",
        email: username_and_email_generator.email,
        username: username_and_email_generator.username,
        user_type: :project_bot,
        skip_confirmation: true # Bot users should always have their emails confirmed.
      }
    end

    def create_personal_access_token(user)
      PersonalAccessTokens::CreateService.new(
        current_user: user, target_user: user, params: personal_access_token_params
      ).execute
    end

    def personal_access_token_params
      {
        name: params[:name] || "#{resource_type}_bot",
        impersonation: false,
        scopes: params[:scopes] || default_scopes,
        expires_at: pat_expiration
      }
    end

    def default_scopes
      Gitlab::Auth.resource_bot_scopes
    end

    def create_membership(resource, user, access_level)
      resource.add_member(user, access_level, expires_at: pat_expiration)
    end

    def pat_expiration
      params[:expires_at].presence || PersonalAccessToken::MAX_PERSONAL_ACCESS_TOKEN_LIFETIME_IN_DAYS.days.from_now
    end

    def log_event(token)
      ::Gitlab::AppLogger.info "PROJECT ACCESS TOKEN CREATION: created_by: #{current_user.username}, project_id: #{resource.id}, token_user: #{token.user.name}, token_id: #{token.id}"
    end

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

    def success(access_token)
      ServiceResponse.success(payload: { access_token: access_token })
    end

    def validate_access_level(access_level)
      return true unless resource.is_a?(Project)
      return true if current_user.bot?
      return true if current_user.can?(:manage_owners, resource)

      current_user.authorized_project?(resource, access_level.to_i)
    end

    def do_not_allow_owner_access_level_for_project_bot?(access_level)
      resource.is_a?(Project) &&
        access_level.to_i == Gitlab::Access::OWNER &&
        !current_user.can?(:manage_owners, resource)
    end
  end
end

ResourceAccessTokens::CreateService.prepend_mod_with('ResourceAccessTokens::CreateService')

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe ResourceAccessTokens::CreateService, feature_category: :system_access do
  subject { described_class.new(user, resource, params).execute }

  let_it_be(:user) { create(:user) }
  let_it_be(:project) { create(:project, :private) }
  let_it_be(:group) { create(:group, :private) }
  let_it_be(:params) { {} }
  let_it_be(:max_pat_access_token_lifetime) do
    PersonalAccessToken::MAX_PERSONAL_ACCESS_TOKEN_LIFETIME_IN_DAYS.days.from_now.to_date.freeze
  end

  before do
    stub_config_setting(host: 'example.com')
  end

  describe '#execute' do
    shared_examples 'token creation fails' do
      let(:resource) { create(:project) }

      it 'does not add the project bot as a member' do
        expect { subject }.not_to change { resource.members.count }
      end

      it 'immediately destroys the bot user if one was created', :sidekiq_inline do
        expect { subject }.not_to change { User.bots.count }
      end
    end

    shared_examples 'correct error message' do
      it 'returns correct error message' do
        expect(subject.error?).to be true
        expect(subject.errors).to include(error_message)
      end
    end

    shared_examples 'allows creation of bot with valid params' do
      it { expect { subject }.to change { User.count }.by(1) }

      it 'creates resource bot user' do
        response = subject

        access_token = response.payload[:access_token]

        expect(access_token.user.reload.user_type).to eq("project_bot")
        expect(access_token.user.created_by_id).to eq(user.id)
      end

      context 'email confirmation status' do
        shared_examples_for 'creates a user that has their email confirmed' do
          it 'creates a user that has their email confirmed' do
            response = subject
            access_token = response.payload[:access_token]

            expect(access_token.user.reload.confirmed?).to eq(true)
          end
        end

        context 'when created by an admin' do
          let(:user) { create(:admin) }

          context 'when admin mode is enabled', :enable_admin_mode do
            it_behaves_like 'creates a user that has their email confirmed'
          end

          context 'when admin mode is disabled' do
            it 'returns error' do
              response = subject

              expect(response.error?).to be true
            end
          end
        end

        context 'when created by a non-admin' do
          it_behaves_like 'creates a user that has their email confirmed'
        end
      end

      context 'bot name' do
        context 'when no name is passed' do
          it 'uses default name' do
            response = subject
            access_token = response.payload[:access_token]

            expect(access_token.user.name).to eq("#{resource.name.to_s.humanize} bot")
          end
        end

        context 'when user provides name' do
          let_it_be(:params) { { name: 'Random bot' } }

          it 'overrides the default name value' do
            response = subject
            access_token = response.payload[:access_token]

            expect(access_token.user.name).to eq(params[:name])
          end
        end
      end

      context 'bot username and email' do
        include_examples 'username and email pair is generated by Gitlab::Utils::UsernameAndEmailGenerator' do
          subject do
            response = described_class.new(user, resource, params).execute
            response.payload[:access_token].user
          end

          let(:username_prefix) do
            "#{resource.class.name.downcase}_#{resource.id}_bot"
          end

          let(:email_domain) do
            "noreply.#{Gitlab.config.gitlab.host}"
          end
        end
      end

      context 'access level' do
        context 'when user does not specify an access level' do
          it 'adds the bot user as a maintainer in the resource' do
            response = subject
            access_token = response.payload[:access_token]
            bot_user = access_token.user

            expect(resource.members.maintainers.map(&:user_id)).to include(bot_user.id)
          end
        end

        shared_examples 'bot with access level' do
          it 'adds the bot user with the specified access level in the resource' do
            response = subject
            access_token = response.payload[:access_token]
            bot_user = access_token.user

            expect(resource.members.developers.map(&:user_id)).to include(bot_user.id)
          end
        end

        context 'when user specifies an access level' do
          let_it_be(:params) { { access_level: Gitlab::Access::DEVELOPER } }

          it_behaves_like 'bot with access level'
        end

        context 'with DEVELOPER access_level, in string format' do
          let_it_be(:params) { { access_level: Gitlab::Access::DEVELOPER.to_s } }

          it_behaves_like 'bot with access level'
        end

        context 'when user is external' do
          before do
            user.update!(external: true)
          end

          it 'creates resource bot user with external status' do
            expect(subject.payload[:access_token].user.external).to eq true
          end
        end
      end

      context 'personal access token' do
        it { expect { subject }.to change { PersonalAccessToken.count }.by(1) }

        context 'when user does not provide scope' do
          it 'has default scopes' do
            response = subject
            access_token = response.payload[:access_token]

            expect(access_token.scopes).to eq(Gitlab::Auth.resource_bot_scopes)
          end
        end

        context 'when user provides scope explicitly' do
          let_it_be(:params) { { scopes: Gitlab::Auth::REPOSITORY_SCOPES } }

          it 'overrides the default scope value' do
            response = subject
            access_token = response.payload[:access_token]

            expect(access_token.scopes).to eq(Gitlab::Auth::REPOSITORY_SCOPES)
          end
        end

        context 'expires_at' do
          context 'when no expiration value is passed' do
            it 'defaults to PersonalAccessToken::MAX_PERSONAL_ACCESS_TOKEN_LIFETIME_IN_DAYS' do
              freeze_time do
                response = subject
                access_token = response.payload[:access_token]

                expect(access_token.expires_at).to eq(
                  max_pat_access_token_lifetime.to_date
                )
              end
            end

            it 'project bot membership expires when PAT expires' do
              response = subject
              access_token = response.payload[:access_token]
              project_bot = access_token.user

              expect(resource.members.find_by(user_id: project_bot.id).expires_at).to eq(
                max_pat_access_token_lifetime.to_date
              )
            end
          end

          context 'when user provides expiration value' do
            let_it_be(:params) { { expires_at: Date.today + 1.month } }

            it 'overrides the default expiration value' do
              response = subject
              access_token = response.payload[:access_token]

              expect(access_token.expires_at).to eq(params[:expires_at])
            end

            context 'expiry of the project bot member' do
              it 'sets the project bot to expire on the same day as the token' do
                response = subject
                access_token = response.payload[:access_token]
                project_bot = access_token.user

                expect(resource.members.find_by(user_id: project_bot.id).expires_at).to eq(access_token.expires_at)
              end
            end
          end

          context 'when invalid scope is passed' do
            let(:error_message) { 'Scopes can only contain available scopes' }
            let_it_be(:params) { { scopes: [:invalid_scope] } }

            it_behaves_like 'token creation fails'
            it_behaves_like 'correct error message'
          end
        end

        context "when access provisioning fails" do
          let_it_be(:bot_user) { create(:user, :project_bot) }

          let(:unpersisted_member) { build(:project_member, source: resource, user: bot_user) }
          let(:error_message) { 'Could not provision maintainer access to the access token. ERROR: error message' }

          before do
            allow_next_instance_of(ResourceAccessTokens::CreateService) do |service|
              allow(service).to receive(:create_user).and_return(bot_user)
              allow(service).to receive(:create_membership).and_return(unpersisted_member)
            end

            allow(unpersisted_member).to receive_message_chain(:errors, :full_messages, :to_sentence)
              .and_return('error message')
          end

          context 'with MAINTAINER access_level, in integer format' do
            let_it_be(:params) { { access_level: Gitlab::Access::MAINTAINER } }

            it_behaves_like 'token creation fails'
            it_behaves_like 'correct error message'
          end

          context 'with MAINTAINER access_level, in string format' do
            let_it_be(:params) { { access_level: Gitlab::Access::MAINTAINER.to_s } }

            it_behaves_like 'token creation fails'
            it_behaves_like 'correct error message'
          end
        end
      end

      it 'logs the event' do
        allow(Gitlab::AppLogger).to receive(:info)

        response = subject

        expect(Gitlab::AppLogger).to have_received(:info).with(/PROJECT ACCESS TOKEN CREATION: created_by: #{user.username}, project_id: #{resource.id}, token_user: #{response.payload[:access_token].user.name}, token_id: \d+/)
      end
    end

    shared_examples 'when user does not have permission to create a resource bot' do
      let(:error_message) { "User does not have permission to create #{resource_type} access token" }

      it_behaves_like 'token creation fails'
      it_behaves_like 'correct error message'
    end

    context 'when resource is a project' do
      let_it_be(:resource_type) { 'project' }
      let_it_be(:resource) { project }

      it_behaves_like 'when user does not have permission to create a resource bot'

      context 'user with valid permission' do
        before_all do
          resource.add_maintainer(user)
        end

        it_behaves_like 'allows creation of bot with valid params'

        context 'when user specifies an access level of OWNER for the bot' do
          let_it_be(:params) { { access_level: Gitlab::Access::OWNER } }

          context 'when the executor is a MAINTAINER' do
            let(:error_message) { 'Could not provision owner access to project access token' }

            context 'with OWNER access_level, in integer format' do
              it_behaves_like 'token creation fails'
              it_behaves_like 'correct error message'
            end

            context 'with OWNER access_level, in string format' do
              let(:error_message) { 'Could not provision owner access to project access token' }
              let_it_be(:params) { { access_level: Gitlab::Access::OWNER.to_s } }

              it_behaves_like 'token creation fails'
              it_behaves_like 'correct error message'
            end
          end

          context 'when the executor is an OWNER' do
            let_it_be(:user) { project.first_owner }

            it 'adds the bot user with the specified access level in the resource' do
              response = subject

              access_token = response.payload[:access_token]
              bot_user = access_token.user

              expect(resource.members.owners.map(&:user_id)).to include(bot_user.id)
            end
          end
        end
      end
    end

    context 'when resource is a group' do
      let_it_be(:resource_type) { 'group' }
      let_it_be(:resource) { group }

      it_behaves_like 'when user does not have permission to create a resource bot'

      context 'user with valid permission' do
        before_all do
          resource.add_owner(user)
        end

        it_behaves_like 'allows creation of bot with valid params'

        context 'when user specifies an access level of OWNER for the bot' do
          let_it_be(:params) { { access_level: Gitlab::Access::OWNER } }

          it 'adds the bot user with the specified access level in the resource' do
            response = subject
            access_token = response.payload[:access_token]
            bot_user = access_token.user

            expect(resource.members.owners.map(&:user_id)).to include(bot_user.id)
          end
        end
      end
    end
  end
end


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

module Repositories
  class ReplicateService < Repositories::BaseService
    Error = Class.new(StandardError)

    def execute(new_repository, type)
      new_repository.replicate(repository)

      new_checksum = new_repository.checksum
      checksum = repository.checksum

      return if new_checksum == checksum

      raise Error, format(s_(
        'ReplicateService|Failed to verify %{type} repository checksum from %{old} to %{new}'
      ), type: type, old: checksum, new: new_checksum)
    rescue StandardError => e
      new_repository.remove

      raise e
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Repositories::ReplicateService, feature_category: :source_code_management do
  let(:new_checksum) { 'match' }
  let(:repository) { instance_double('Gitlab::Git::Repository', checksum: 'match') }
  let(:new_repository) { instance_double('Gitlab::Git::Repository', checksum: new_checksum) }

  subject { described_class.new(repository) }

  it 'replicates repository' do
    expect(new_repository).to receive(:replicate).with(repository)
    expect(new_repository).not_to receive(:remove)

    expect { subject.execute(new_repository, :project) }.not_to raise_error
  end

  context 'when checksum does not match' do
    let(:new_checksum) { 'does not match' }

    it 'raises an error and removes new repository' do
      expect(new_repository).to receive(:replicate).with(repository)
      expect(new_repository).to receive(:remove)

      expect do
        subject.execute(new_repository, :project)
      end.to raise_error(described_class::Error, /Failed to verify project repository/)
    end
  end

  context 'when an error is raised during checksum calculation' do
    it 'raises the error and removes new repository' do
      error = StandardError.new

      expect(new_repository).to receive(:replicate).with(repository)
      expect(new_repository).to receive(:checksum).and_raise(error)
      expect(new_repository).to receive(:remove)

      expect do
        subject.execute(new_repository, :project)
      end.to raise_error(error)
    end
  end
end


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

# Used for git housekeeping
#
# Ex.
#   Repositories::HousekeepingService.new(project).execute
#   Repositories::HousekeepingService.new(project.wiki).execute
#
module Repositories
  class HousekeepingService < BaseService
    # Timeout set to 24h
    LEASE_TIMEOUT = 86400
    GC_PERIOD = 200

    class LeaseTaken < StandardError
      def to_s
        "Somebody already triggered housekeeping for this resource in the past #{LEASE_TIMEOUT / 60} minutes"
      end
    end

    def initialize(resource, task = nil)
      @resource = resource
      @task = task
    end

    def execute
      lease_uuid = try_obtain_lease
      raise LeaseTaken unless lease_uuid.present?

      yield if block_given?

      execute_gitlab_shell_gc(lease_uuid)
    end

    def needed?
      pushes_since_gc > 0 && period_match? && housekeeping_enabled?
    end

    def increment!
      Gitlab::Metrics.measure(:increment_pushes_since_gc) do
        @resource.increment_pushes_since_gc
      end
    end

    private

    def execute_gitlab_shell_gc(lease_uuid)
      @resource.git_garbage_collect_worker_klass.perform_async(@resource.id, task, lease_key, lease_uuid)
    ensure
      if pushes_since_gc >= gc_period
        Gitlab::Metrics.measure(:reset_pushes_since_gc) do
          @resource.reset_pushes_since_gc
        end
      end
    end

    def try_obtain_lease
      Gitlab::Metrics.measure(:obtain_housekeeping_lease) do
        lease = ::Gitlab::ExclusiveLease.new(lease_key, timeout: LEASE_TIMEOUT)
        lease.try_obtain
      end
    end

    def lease_key
      "#{@resource.class.name.underscore.pluralize}_housekeeping:#{@resource.id}"
    end

    def pushes_since_gc
      @resource.pushes_since_gc
    end

    def task
      return @task if @task

      if pushes_since_gc % gc_period == 0
        :gc
      else
        :incremental_repack
      end
    end

    def period_match?
      [gc_period, repack_period].any? { |period| pushes_since_gc % period == 0 }
    end

    def housekeeping_enabled?
      Gitlab::CurrentSettings.housekeeping_enabled
    end

    def gc_period
      GC_PERIOD
    end

    def repack_period
      Gitlab::CurrentSettings.housekeeping_incremental_repack_period
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Repositories::HousekeepingService, feature_category: :source_code_management do
  it_behaves_like 'housekeeps repository' do
    let_it_be(:resource) { create(:project, :repository) }
  end

  it_behaves_like 'housekeeps repository' do
    let_it_be(:project) { create(:project, :wiki_repo) }
    let_it_be(:resource) { project.wiki }
  end
end


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

module Repositories
  # A service class for generating a changelog section.
  class ChangelogService
    DEFAULT_TRAILER = 'Changelog'
    DEFAULT_FILE = 'CHANGELOG.md'

    # The maximum number of commits allowed to fetch in `from` and `to` range.
    #
    # This value is arbitrarily chosen. Increasing it means more Gitaly calls
    # and more presure on Gitaly services.
    #
    # This number is 3x of the average number of commits per GitLab releases.
    # Some examples for GitLab's own releases:
    #
    # * 13.6.0: 4636 commits
    # * 13.5.0: 5912 commits
    # * 13.4.0: 5541 commits
    COMMITS_LIMIT = 15_000

    # The `project` specifies the `Project` to generate the changelog section
    # for.
    #
    # The `user` argument specifies a `User` to use for committing the changes
    # to the Git repository.
    #
    # The `version` arguments must be a version `String` using semantic
    # versioning as the format.
    #
    # The arguments `from` and `to` must specify a Git ref or SHA to use for
    # fetching the commits to include in the changelog. The SHA/ref set in the
    # `from` argument isn't included in the list.
    #
    # The `date` argument specifies the date of the release, and defaults to the
    # current time/date.
    #
    # The `branch` argument specifies the branch to commit the changes to. The
    # branch must already exist.
    #
    # The `trailer` argument is the Git trailer to use for determining what
    # commits to include in the changelog.
    #
    # The `config_file` arguments specifies the path to the configuration file as
    # stored in the project's Git repository.
    #
    # The `file` arguments specifies the name/path of the file to commit the
    # changes to. If the file doesn't exist, it's created automatically.
    #
    # The `message` argument specifies the commit message to use when committing
    # the changelog changes.
    #
    # rubocop: disable Metrics/ParameterLists
    def initialize(
      project,
      user,
      version:,
      branch: project.default_branch_or_main,
      from: nil,
      to: branch,
      date: DateTime.now,
      trailer: DEFAULT_TRAILER,
      config_file: Gitlab::Changelog::Config::DEFAULT_FILE_PATH,
      file: DEFAULT_FILE,
      message: "Add changelog for version #{version}"
    )
      @project = project
      @user = user
      @version = version
      @from = from
      @to = to
      @date = date
      @branch = branch
      @trailer = trailer
      @config_file = config_file
      @file = file
      @message = message
    end
    # rubocop: enable Metrics/ParameterLists

    def execute(commit_to_changelog: true)
      config = Gitlab::Changelog::Config.from_git(@project, @user, @config_file)
      from = start_of_commit_range(config)

      # For every entry we want to only include the merge request that
      # originally introduced the commit, which is the oldest merge request that
      # contains the commit. We fetch there merge requests in batches, reducing
      # the number of SQL queries needed to get this data.
      mrs_finder = MergeRequests::OldestPerCommitFinder.new(@project)
      release = Gitlab::Changelog::Release
        .new(version: @version, date: @date, config: config)

      commits =
        ChangelogCommitsFinder.new(project: @project, from: from, to: @to)

      verify_commit_range!(from, @to)

      commits.each_page(@trailer) do |page|
        mrs = mrs_finder.execute(page)

        # Preload the authors. This ensures we only need a single SQL query per
        # batch of commits, instead of needing a query for every commit.
        page.each(&:lazy_author)

        # Preload author permissions
        @project.team.max_member_access_for_user_ids(page.map(&:author).compact.map(&:id))

        page.each do |commit|
          release.add_entry(
            title: commit.title,
            commit: commit,
            category: commit.trailers.fetch(@trailer),
            author: commit.author,
            merge_request: mrs[commit.id]
          )
        end
      end

      if commit_to_changelog
        Gitlab::Changelog::Committer
          .new(@project, @user)
          .commit(release: release, file: @file, branch: @branch, message: @message)
      else
        Gitlab::Changelog::Generator.new.add(release)
      end
    end

    def start_of_commit_range(config)
      return @from if @from

      finder = ChangelogTagFinder.new(@project, regex: config.tag_regex)

      if (prev_tag = finder.execute(@version))
        return prev_tag.target_commit.id
      end

      raise(
        Gitlab::Changelog::Error,
        'The commit start range is unspecified, and no previous tag ' \
          'could be found to use instead'
      )
    end

    def verify_commit_range!(from, to)
      return unless Feature.enabled?(:changelog_commits_limitation, @project)

      commits = @project.repository.commits_by(oids: [from, to])

      raise Gitlab::Changelog::Error, "Invalid or not found commit value in the given range" unless commits.count == 2

      _, commits_count = @project.repository.diverging_commit_count(from, to)

      if commits_count > COMMITS_LIMIT
        raise Gitlab::Changelog::Error, "The commits range exceeds #{COMMITS_LIMIT} elements."
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Repositories::ChangelogService, feature_category: :source_code_management do
  describe '#execute' do
    let!(:project) { create(:project, :empty_repo) }
    let!(:creator) { project.creator }
    let!(:author1) { create(:user) }
    let!(:author2) { create(:user) }
    let!(:mr1) { create(:merge_request, :merged, target_project: project) }
    let!(:mr2) { create(:merge_request, :merged, target_project: project) }

    # The range of commits ignores the first commit, but includes the last
    # commit. To ensure both the commits below are included, we must create an
    # extra commit.
    #
    # In the real world, the start commit of the range will be the last commit
    # of the previous release, so ignoring that is expected and desired.
    let!(:sha1) do
      create_commit(
        project,
        creator,
        commit_message: 'Initial commit',
        actions: [{ action: 'create', content: 'test', file_path: 'README.md' }]
      )
    end

    let!(:sha2) do
      project.add_maintainer(author1)

      create_commit(
        project,
        author1,
        commit_message: "Title 1\n\nChangelog: feature",
        actions: [{ action: 'create', content: 'foo', file_path: 'a.txt' }]
      )
    end

    let!(:sha3) do
      project.add_maintainer(author2)

      create_commit(
        project,
        author2,
        commit_message: "Title 2\n\nChangelog: feature",
        actions: [{ action: 'create', content: 'bar', file_path: 'b.txt' }]
      )
    end

    let!(:sha4) do
      create_commit(
        project,
        author2,
        commit_message: "Title 3\n\nChangelog: feature",
        actions: [{ action: 'create', content: 'bar', file_path: 'c.txt' }]
      )
    end

    let!(:commit1) { project.commit(sha2) }
    let!(:commit2) { project.commit(sha3) }
    let!(:commit3) { project.commit(sha4) }

    let(:commit_to_changelog) { true }

    it 'generates and commits a changelog section' do
      allow(MergeRequestDiffCommit)
        .to receive(:oldest_merge_request_id_per_commit)
        .with(project.id, [commit2.id, commit1.id])
        .and_return(
          [
            { sha: sha2, merge_request_id: mr1.id },
            { sha: sha3, merge_request_id: mr2.id }
          ])

      service = described_class
        .new(project, creator, version: '1.0.0', from: sha1, to: sha3)

      recorder = ActiveRecord::QueryRecorder.new { service.execute(commit_to_changelog: commit_to_changelog) }
      changelog = project.repository.blob_at('master', 'CHANGELOG.md')&.data

      expect(recorder.count).to eq(12)
      expect(changelog).to include('Title 1', 'Title 2')
    end

    it "ignores a commit when it's both added and reverted in the same range" do
      create_commit(
        project,
        author2,
        commit_message: "Title 4\n\nThis reverts commit #{sha4}",
        actions: [{ action: 'create', content: 'bar', file_path: 'd.txt' }]
      )

      described_class
        .new(project, creator, version: '1.0.0', from: sha1)
        .execute(commit_to_changelog: commit_to_changelog)

      changelog = project.repository.blob_at('master', 'CHANGELOG.md')&.data

      expect(changelog).to include('Title 1', 'Title 2')
      expect(changelog).not_to include('Title 3', 'Title 4')
    end

    it 'includes a revert commit when it has a trailer' do
      create_commit(
        project,
        author2,
        commit_message: "Title 4\n\nThis reverts commit #{sha4}\n\nChangelog: added",
        actions: [{ action: 'create', content: 'bar', file_path: 'd.txt' }]
      )

      described_class
        .new(project, creator, version: '1.0.0', from: sha1)
        .execute(commit_to_changelog: commit_to_changelog)

      changelog = project.repository.blob_at('master', 'CHANGELOG.md')&.data

      expect(changelog).to include('Title 1', 'Title 2', 'Title 4')
      expect(changelog).not_to include('Title 3')
    end

    it 'uses the target branch when "to" is unspecified' do
      described_class
        .new(project, creator, version: '1.0.0', from: sha1)
        .execute(commit_to_changelog: commit_to_changelog)

      changelog = project.repository.blob_at('master', 'CHANGELOG.md')&.data

      expect(changelog).to include('Title 1', 'Title 2', 'Title 3')
    end

    describe 'with commit_to_changelog: false' do
      let(:commit_to_changelog) { false }

      it 'generates changelog section' do
        allow(MergeRequestDiffCommit)
          .to receive(:oldest_merge_request_id_per_commit)
          .with(project.id, [commit2.id, commit1.id])
          .and_return(
            [
              { sha: sha2, merge_request_id: mr1.id },
              { sha: sha3, merge_request_id: mr2.id }
            ])

        service = described_class
          .new(project, creator, version: '1.0.0', from: sha1, to: sha3)

        changelog = service.execute(commit_to_changelog: commit_to_changelog)

        expect(changelog).to include('Title 1', 'Title 2')
      end
    end

    it 'avoids N+1 queries', :request_store do
      RequestStore.clear!

      request = ->(to) do
        described_class
          .new(project, creator, version: '1.0.0', from: sha1, to: to)
          .execute(commit_to_changelog: false)
      end

      control = ActiveRecord::QueryRecorder.new { request.call(sha2) }

      RequestStore.clear!

      expect { request.call(sha3) }.not_to exceed_query_limit(control.count)
    end

    context 'when one of commits does not exist' do
      let(:service) { described_class.new(project, creator, version: '1.0.0', from: 'master', to: '54321') }

      it 'raises an exception' do
        expect { service.execute(commit_to_changelog: false) }.to raise_error(Gitlab::Changelog::Error)
      end
    end

    context 'when commit range exceeds the limit' do
      let(:service) { described_class.new(project, creator, version: '1.0.0', from: sha1) }

      before do
        stub_const("#{described_class.name}::COMMITS_LIMIT", 2)
      end

      it 'raises an exception' do
        expect { service.execute(commit_to_changelog: false) }.to raise_error(Gitlab::Changelog::Error)
      end

      context 'when feature flag is off' do
        before do
          stub_feature_flags(changelog_commits_limitation: false)
        end

        it 'returns the changelog' do
          expect(service.execute(commit_to_changelog: false)).to include('Title 1', 'Title 2', 'Title 3')
        end
      end
    end

    context 'with specified changelog config file path' do
      it 'return specified changelog content' do
        config = Gitlab::Changelog::Config.from_hash(project, { 'template' => 'specified_changelog_content' }, creator)

        allow(Gitlab::Changelog::Config)
          .to receive(:from_git)
          .with(project, creator, 'specified_changelog_config.yml')
          .and_return(config)

        described_class
          .new(project, creator, version: '1.0.0', from: sha1, config_file: 'specified_changelog_config.yml')
          .execute(commit_to_changelog: commit_to_changelog)

        changelog = project.repository.blob_at('master', 'CHANGELOG.md')&.data

        expect(changelog).to include('specified_changelog_content')
      end
    end
  end

  describe '#start_of_commit_range' do
    let(:project) { build_stubbed(:project) }
    let(:user) { build_stubbed(:user) }
    let(:config) { Gitlab::Changelog::Config.new(project) }

    context 'when the "from" argument is specified' do
      it 'returns the value of the argument' do
        service = described_class
          .new(project, user, version: '1.0.0', from: 'foo', to: 'bar')

        expect(service.start_of_commit_range(config)).to eq('foo')
      end
    end

    context 'when the "from" argument is unspecified' do
      it 'returns the tag commit of the previous version' do
        service = described_class
          .new(project, user, version: '1.0.0', to: 'bar')

        finder_spy = instance_spy(Repositories::ChangelogTagFinder)
        tag = double(:tag, target_commit: double(:commit, id: '123'))

        allow(Repositories::ChangelogTagFinder)
          .to receive(:new)
          .with(project, regex: an_instance_of(String))
          .and_return(finder_spy)

        allow(finder_spy)
          .to receive(:execute)
          .with('1.0.0')
          .and_return(tag)

        expect(service.start_of_commit_range(config)).to eq('123')
      end

      it 'raises an error when no tag is found' do
        service = described_class
          .new(project, user, version: '1.0.0', to: 'bar')

        finder_spy = instance_spy(Repositories::ChangelogTagFinder)

        allow(Repositories::ChangelogTagFinder)
          .to receive(:new)
          .with(project, regex: an_instance_of(String))
          .and_return(finder_spy)

        allow(finder_spy)
          .to receive(:execute)
          .with('1.0.0')
          .and_return(nil)

        expect { service.start_of_commit_range(config) }
          .to raise_error(Gitlab::Changelog::Error)
      end
    end
  end

  def create_commit(project, user, params)
    params = { start_branch: 'master', branch_name: 'master' }.merge(params)
    Files::MultiService.new(project, user, params).execute.fetch(:result)
  end
end


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

class Repositories::DestroyService < Repositories::BaseService
  def execute
    return success unless repository
    return success unless repo_exists?(disk_path)

    # Flush the cache for both repositories. This has to be done _before_
    # removing the physical repositories as some expiration code depends on
    # Git data (e.g. a list of branch names).
    ignore_git_errors { repository.before_delete }

    # Use variables that aren't methods on Project, because they are used in a callback
    current_storage = repository.shard
    current_path = "#{disk_path}.git"

    # Because #remove happens inside a run_after_commit callback it will
    # never be triggered on a read-only instance.
    #
    # Issue: https://gitlab.com/gitlab-org/gitlab/-/issues/223272
    if Gitlab::Database.read_only?
      Gitlab::Git::Repository.new(current_storage, current_path, nil, nil).remove
    else
      container.run_after_commit do
        Gitlab::Git::Repository.new(current_storage, current_path, nil, nil).remove
      end
    end

    log_info("Repository \"#{full_path}\" was removed")

    success
  rescue Gitlab::Git::Repository::NoRepository
    success
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Repositories::DestroyService, feature_category: :source_code_management do
  let_it_be(:user) { create(:user) }

  let!(:project) { create(:project, :repository, namespace: user.namespace) }
  let(:repository) { project.repository }
  let(:path) { repository.disk_path }

  subject { described_class.new(repository).execute }

  it 'removes the repository' do
    expect(project.gitlab_shell.repository_exists?(project.repository_storage, path + '.git')).to be_truthy

    subject

    # Because the removal happens inside a run_after_commit callback we need to
    # trigger the callback
    project.touch

    expect(project.gitlab_shell.repository_exists?(project.repository_storage, path + '.git')).to be_falsey
  end

  context 'on a read-only instance' do
    before do
      allow(Gitlab::Database).to receive(:read_only?).and_return(true)
    end

    it 'schedules the repository deletion' do
      expect(project.gitlab_shell.repository_exists?(project.repository_storage, path + '.git')).to be_truthy

      subject

      expect(project.gitlab_shell.repository_exists?(project.repository_storage, path + '.git')).to be_falsey
    end
  end

  it 'flushes the repository cache' do
    expect(repository).to receive(:before_delete)

    subject
  end

  it 'does not perform any action if repository path does not exist and returns success' do
    expect(repository).to receive(:disk_path).and_return('foo')
    expect(repository).not_to receive(:before_delete)

    expect(subject[:status]).to eq :success
  end

  it 'gracefully handles exception if the repository does not exist on disk' do
    expect(repository).to receive(:before_delete).and_raise(Gitlab::Git::Repository::NoRepository)
    expect(subject[:status]).to eq :success
  end

  context 'with a project wiki repository' do
    let(:project) { create(:project, :wiki_repo) }
    let(:repository) { project.wiki.repository }

    it 'schedules the repository deletion' do
      expect(project.gitlab_shell.repository_exists?(project.repository_storage, path + '.git')).to be_truthy

      subject

      # Because the removal happens inside a run_after_commit callback we need to
      # trigger the callback
      project.touch

      expect(project.gitlab_shell.repository_exists?(project.repository_storage, path + '.git')).to be_falsey
    end
  end
end


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

module Groups
  # Service class for counting and caching the number of open merge requests of a group.
  class MergeRequestsCountService < Groups::CountService
    private

    def cache_key_name
      'open_merge_requests_count'
    end

    def relation_for_count
      MergeRequestsFinder
      .new(user, group_id: group.id, state: 'opened', non_archived: true, include_subgroups: true)
      .execute
    end

    def issuable_key
      'open_merge_requests'
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Groups::MergeRequestsCountService, :use_clean_rails_memory_store_caching, feature_category: :groups_and_projects do
  let_it_be(:user) { create(:user) }
  let_it_be(:group) { create(:group, :public) }
  let_it_be(:project) { create(:project, :repository, namespace: group) }
  let_it_be(:merge_request) { create(:merge_request, source_project: project, target_project: project) }

  subject { described_class.new(group, user) }

  describe '#relation_for_count' do
    before do
      group.add_reporter(user)
      allow(MergeRequestsFinder).to receive(:new).and_call_original
    end

    it 'uses the MergeRequestsFinder to scope merge requests' do
      expect(MergeRequestsFinder)
        .to receive(:new)
        .with(user, group_id: group.id, state: 'opened', non_archived: true, include_subgroups: true)

      subject.count
    end
  end

  it_behaves_like 'a counter caching service with threshold'
end


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

module Groups
  class AutocompleteService < Groups::BaseService
    include LabelsAsHash

    # rubocop: disable CodeReuse/ActiveRecord
    def issues(confidential_only: false, issue_types: nil)
      finder_params = { group_id: group.id, include_subgroups: true, state: 'opened' }
      finder_params[:confidential] = true if confidential_only.present?
      finder_params[:issue_types] = issue_types if issue_types.present?

      IssuesFinder.new(current_user, finder_params)
        .execute
        .preload(project: :namespace)
        .select(:iid, :title, :project_id, :namespace_id)
    end
    # rubocop: enable CodeReuse/ActiveRecord

    # rubocop: disable CodeReuse/ActiveRecord
    def merge_requests
      MergeRequestsFinder.new(current_user, group_id: group.id, include_subgroups: true, state: 'opened')
        .execute
        .preload(target_project: :namespace)
        .select(:iid, :title, :target_project_id)
    end
    # rubocop: enable CodeReuse/ActiveRecord

    # rubocop: disable CodeReuse/ActiveRecord
    def milestones
      group_ids = group.self_and_ancestors.public_or_visible_to_user(current_user).pluck(:id)

      MilestonesFinder.new(group_ids: group_ids).execute.select(:iid, :title, :due_date)
    end
    # rubocop: enable CodeReuse/ActiveRecord

    def labels_as_hash(target)
      super(target, group_id: group.id, only_group_labels: true, include_ancestor_groups: true)
    end

    def commands(noteable)
      return [] unless noteable

      QuickActions::InterpretService.new(nil, current_user).available_commands(noteable)
    end
  end
end

Groups::AutocompleteService.prepend_mod

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Groups::AutocompleteService, feature_category: :groups_and_projects do
  let_it_be(:group, refind: true) { create(:group, :nested, :private, avatar: fixture_file_upload('spec/fixtures/dk.png')) }
  let_it_be(:sub_group) { create(:group, :private, parent: group) }

  let(:user) { create(:user) }

  subject { described_class.new(group, user) }

  before do
    group.add_developer(user)
  end

  def expect_labels_to_equal(labels, expected_labels)
    extract_title = lambda { |label| label['title'] }
    expect(labels.map(&extract_title)).to match_array(expected_labels.map(&extract_title))
  end

  describe '#labels_as_hash' do
    let!(:label1) { create(:group_label, group: group) }
    let!(:label2) { create(:group_label, group: group) }
    let!(:sub_group_label) { create(:group_label, group: sub_group) }
    let!(:parent_group_label) { create(:group_label, group: group.parent) }

    it 'returns labels from own group and ancestor groups' do
      results = subject.labels_as_hash(nil)

      expected_labels = [label1, label2, parent_group_label]

      expect_labels_to_equal(results, expected_labels)
    end
  end

  describe '#issues' do
    let(:project) { create(:project, group: group) }
    let(:sub_group_project) { create(:project, group: sub_group) }

    let!(:project_issue) { create(:issue, project: project) }
    let!(:sub_group_project_issue) { create(:issue, confidential: true, project: sub_group_project) }

    it 'returns issues in group and subgroups' do
      issues = subject.issues

      expect(issues.map(&:iid)).to contain_exactly(project_issue.iid, sub_group_project_issue.iid)
      expect(issues.map(&:title)).to contain_exactly(project_issue.title, sub_group_project_issue.title)
    end

    it 'returns only confidential issues if confidential_only is true' do
      issues = subject.issues(confidential_only: true)

      expect(issues.map(&:iid)).to contain_exactly(sub_group_project_issue.iid)
      expect(issues.map(&:title)).to contain_exactly(sub_group_project_issue.title)
    end
  end

  describe '#merge_requests' do
    let(:project) { create(:project, :repository, group: group) }
    let(:sub_group_project) { create(:project, :repository, group: sub_group) }

    let!(:project_mr) { create(:merge_request, source_project: project) }
    let!(:sub_group_project_mr) { create(:merge_request, source_project: sub_group_project) }

    it 'returns merge requests in group and subgroups' do
      expect(subject.merge_requests.map(&:iid)).to contain_exactly(project_mr.iid, sub_group_project_mr.iid)
      expect(subject.merge_requests.map(&:title)).to contain_exactly(project_mr.title, sub_group_project_mr.title)
    end
  end

  describe '#milestones' do
    let!(:group_milestone) { create(:milestone, group: group) }
    let!(:subgroup_milestone) { create(:milestone, group: sub_group) }

    before do
      sub_group.add_maintainer(user)
    end

    context 'when group is public' do
      let(:public_group) { create(:group, :public) }
      let(:public_subgroup) { create(:group, :public, parent: public_group) }

      before do
        group_milestone.update!(group: public_group)
        subgroup_milestone.update!(group: public_subgroup)
      end

      it 'returns milestones from groups and subgroups' do
        subject = described_class.new(public_subgroup, user)

        expect(subject.milestones.map(&:iid)).to contain_exactly(group_milestone.iid, subgroup_milestone.iid)
        expect(subject.milestones.map(&:title)).to contain_exactly(group_milestone.title, subgroup_milestone.title)
      end
    end

    it 'returns milestones from group' do
      expect(subject.milestones.map(&:iid)).to contain_exactly(group_milestone.iid)
      expect(subject.milestones.map(&:title)).to contain_exactly(group_milestone.title)
    end

    it 'returns milestones from groups and subgroups' do
      milestones = described_class.new(sub_group, user).milestones

      expect(milestones.map(&:iid)).to contain_exactly(group_milestone.iid, subgroup_milestone.iid)
      expect(milestones.map(&:title)).to contain_exactly(group_milestone.title, subgroup_milestone.title)
    end

    it 'returns only milestones that user can read' do
      user = create(:user)
      sub_group.add_guest(user)

      milestones = described_class.new(sub_group, user).milestones

      expect(milestones.map(&:iid)).to contain_exactly(subgroup_milestone.iid)
      expect(milestones.map(&:title)).to contain_exactly(subgroup_milestone.title)
    end
  end
end


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

module Groups
  class ParticipantsService < Groups::BaseService
    include Gitlab::Utils::StrongMemoize
    include Users::ParticipableService

    def execute(noteable)
      @noteable = noteable

      participants =
        noteable_owner +
        participants_in_noteable +
        all_members +
        groups +
        group_hierarchy_users

      render_participants_as_hash(participants.uniq)
    end

    private

    def all_members
      return [] if group.nil? || Feature.enabled?(:disable_all_mention)

      [{ username: "all", name: "All Group Members", count: group.users_count }]
    end

    def group_hierarchy_users
      return [] unless group

      sorted(Autocomplete::GroupUsersFinder.new(group: group).execute)
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Groups::ParticipantsService, feature_category: :groups_and_projects do
  describe '#execute' do
    let_it_be(:developer) { create(:user) }
    let_it_be(:parent_group) { create(:group) }
    let_it_be(:group) { create(:group, parent: parent_group) }
    let_it_be(:subgroup) { create(:group, parent: group) }
    let_it_be(:subproject) { create(:project, group: subgroup) }

    let(:service) { described_class.new(group, developer) }

    subject(:service_result) { service.execute(nil) }

    before_all do
      parent_group.add_developer(developer)
    end

    before do
      stub_feature_flags(disable_all_mention: false)
    end

    it 'includes `All Group Members`' do
      group.add_developer(create(:user))

      # These should not be included in the count for the @all entry
      subgroup.add_developer(create(:user))
      subproject.add_developer(create(:user))

      expect(service_result).to include(a_hash_including({ username: "all", name: "All Group Members", count: 1 }))
    end

    context 'when `disable_all_mention` FF is enabled' do
      before do
        stub_feature_flags(disable_all_mention: true)
      end

      it 'does not include `All Group Members`' do
        expect(service_result).not_to include(a_hash_including({ username: "all", name: "All Group Members" }))
      end
    end

    it 'returns all members in parent groups, sub-groups, and sub-projects' do
      parent_group.add_developer(create(:user))
      subgroup.add_developer(create(:user))
      subproject.add_developer(create(:user))

      expected_users = (group.self_and_hierarchy.flat_map(&:users) + subproject.users)
        .map { |user| user_to_autocompletable(user) }

      expect(expected_users.count).to eq(4)
      expect(service_result).to include(*expected_users)
    end

    context 'when shared with a private group' do
      let_it_be(:private_group_member) { create(:user) }
      let_it_be(:private_group) { create(:group, :private, :nested) }

      before_all do
        private_group.add_owner(private_group_member)

        create(:group_group_link, shared_group: parent_group, shared_with_group: private_group)
      end

      subject(:usernames) { service_result.pluck(:username) }

      it { is_expected.to include(private_group_member.username) }
    end
  end

  def user_to_autocompletable(user)
    {
      type: user.class.name,
      username: user.username,
      name: user.name,
      avatar_url: user.avatar_url,
      availability: user&.status&.availability
    }
  end
end