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

module PersonalAccessTokens
  class RevokeTokenFamilyService
    def initialize(token)
      @token = token
    end

    def execute
      # A token family is a chain of rotated tokens. Once rotated, the previous
      # token is revoked. As a result, a single token id should be returned by
      # this query.
      # rubocop: disable CodeReuse/ActiveRecord
      token_ids = pat_family.active.pluck_primary_key

      # We create another query based on the previous if any id exists. An
      # alternative is to use a single query, like
      # `pat_family.active.update_all(...)`). However, #update_all ignores
      # the CTE, and tries to revoke *all* active tokens.
      PersonalAccessToken.where(id: token_ids).update_all(revoked: true) if token_ids.any?
      # rubocop: enable CodeReuse/ActiveRecord

      ServiceResponse.success
    end

    private

    attr_reader :token

    def pat_family
      # rubocop: disable CodeReuse/ActiveRecord
      cte = Gitlab::SQL::RecursiveCTE.new(:personal_access_tokens_cte)
      personal_access_token_table = Arel::Table.new(:personal_access_tokens)

      cte << PersonalAccessToken
               .select(
                 'personal_access_tokens.id',
                 'personal_access_tokens.revoked',
                 'personal_access_tokens.expires_at')
               .where(personal_access_token_table[:previous_personal_access_token_id].eq(token.id))
      cte << PersonalAccessToken
               .select(
                 'personal_access_tokens.id',
                 'personal_access_tokens.revoked',
                 'personal_access_tokens.expires_at')
               .from([personal_access_token_table, cte.table])
               .where(personal_access_token_table[:previous_personal_access_token_id].eq(cte.table[:id]))
      PersonalAccessToken.with.recursive(cte.to_arel).from(cte.alias_to(personal_access_token_table))
      # rubocop: enable CodeReuse/ActiveRecord
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe PersonalAccessTokens::RevokeTokenFamilyService, feature_category: :system_access do
  describe '#execute' do
    let_it_be(:token_3) { create(:personal_access_token, :revoked) }
    let_it_be(:token_2) { create(:personal_access_token, :revoked, previous_personal_access_token_id: token_3.id) }
    let_it_be(:token_1) { create(:personal_access_token, previous_personal_access_token_id: token_2.id) }

    subject(:response) { described_class.new(token_3).execute }

    it 'revokes the latest token from the chain of rotated tokens' do
      expect(response).to be_success
      expect(token_1.reload).to be_revoked
    end

    it 'does not revoke any active token not in the pat family' do
      unrelated_token = create(:personal_access_token)

      expect(response).to be_success
      expect(unrelated_token.reload).to be_active
    end
  end
end


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

module PersonalAccessTokens
  class CreateService < BaseService
    def initialize(current_user:, target_user:, params: {}, concatenate_errors: true)
      @current_user = current_user
      @target_user = target_user
      @params = params.dup
      @ip_address = @params.delete(:ip_address)
      @concatenate_errors = concatenate_errors
    end

    def execute
      return ServiceResponse.error(message: 'Not permitted to create') unless creation_permitted?

      token = target_user.personal_access_tokens.create(personal_access_token_params)

      if token.persisted?
        log_event(token)
        notification_service.access_token_created(target_user, token.name)
        ServiceResponse.success(payload: { personal_access_token: token })
      else
        message = token.errors.full_messages
        message = message.to_sentence if @concatenate_errors

        ServiceResponse.error(message: message, payload: { personal_access_token: token })
      end
    end

    private

    attr_reader :target_user, :ip_address

    def personal_access_token_params
      {
        name: params[:name],
        impersonation: params[:impersonation] || false,
        scopes: params[:scopes],
        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 creation_permitted?
      Ability.allowed?(current_user, :create_user_personal_access_token, target_user)
    end

    def log_event(token)
      log_info("PAT CREATION: created_by: '#{current_user.username}', created_for: '#{token.user.username}', token_id: '#{token.id}'")
    end
  end
end

PersonalAccessTokens::CreateService.prepend_mod_with('PersonalAccessTokens::CreateService')

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe PersonalAccessTokens::CreateService, feature_category: :system_access do
  shared_examples_for 'a successfully created token' do
    it 'creates personal access token record' do
      expect(subject.success?).to be true
      expect(token.name).to eq(params[:name])
      expect(token.impersonation).to eq(params[:impersonation])
      expect(token.scopes).to eq(params[:scopes])
      expect(token.expires_at).to eq(params[:expires_at])
      expect(token.user).to eq(user)
    end

    it 'logs the event' do
      expect(Gitlab::AppLogger).to receive(:info).with(/PAT CREATION: created_by: '#{current_user.username}', created_for: '#{user.username}', token_id: '\d+'/)

      subject
    end

    it 'notifies the user' do
      expect_next_instance_of(NotificationService) do |notification_service|
        expect(notification_service).to receive(:access_token_created).with(user, params[:name])
      end

      subject
    end
  end

  shared_examples_for 'an unsuccessfully created token' do
    it { expect(subject.success?).to be false }
    it { expect(subject.message).to eq('Not permitted to create') }
    it { expect(token).to be_nil }
  end

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

    let(:current_user) { create(:user) }
    let(:user) { create(:user) }
    let(:params) { { name: 'Test token', impersonation: false, scopes: [:api], expires_at: Date.today + 1.month } }
    let(:service) { described_class.new(current_user: current_user, target_user: user, params: params, concatenate_errors: false) }
    let(:token) { subject.payload[:personal_access_token] }

    context 'when current_user is an administrator' do
      let(:current_user) { create(:admin) }

      context 'when admin mode is enabled', :enable_admin_mode do
        it_behaves_like 'a successfully created token'
      end

      context 'when admin mode is disabled' do
        it_behaves_like 'an unsuccessfully created token'
      end
    end

    context 'when current_user is not an administrator' do
      context 'target_user is not the same as current_user' do
        it_behaves_like 'an unsuccessfully created token'
      end

      context 'target_user is same as current_user' do
        let(:current_user) { user }

        it_behaves_like 'a successfully created token'
      end
    end

    context 'with no expires_at set', :freeze_time do
      let(:params) { { name: 'Test token', impersonation: false, scopes: [:no_valid] } }
      let(:service) { described_class.new(current_user: user, target_user: user, params: params) }

      it { expect(subject.payload[:personal_access_token].expires_at).to eq PersonalAccessToken::MAX_PERSONAL_ACCESS_TOKEN_LIFETIME_IN_DAYS.days.from_now.to_date }
    end

    context 'when invalid scope' do
      let(:params) { { name: 'Test token', impersonation: false, scopes: [:no_valid], expires_at: Date.today + 1.month } }

      context 'when concatenate_errors: true' do
        let(:service) { described_class.new(current_user: user, target_user: user, params: params) }

        it { expect(subject.message).to be_an_instance_of(String) }
      end

      context 'when concatenate_errors: false' do
        let(:service) { described_class.new(current_user: user, target_user: user, params: params, concatenate_errors: false) }

        it { expect(subject.message).to be_an_instance_of(Array) }
      end
    end
  end
end


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

module ExportCsv
  class MapExportFieldsService < BaseService
    attr_reader :fields, :data

    def initialize(fields, data)
      @fields = fields
      @data = data
    end

    def execute
      return data if fields.empty?

      selected_fields_to_hash
    end

    def invalid_fields
      fields.reject { |field| permitted_field?(field) }
    end

    private

    def selected_fields_to_hash
      data.select { |key| requested_field?(key) }
    end

    def requested_field?(field)
      field.downcase.in?(fields.map(&:downcase))
    end

    def permitted_field?(field)
      field.downcase.in?(keys.map(&:downcase))
    end

    def keys
      data.keys
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe ExportCsv::MapExportFieldsService, feature_category: :team_planning do
  let(:selected_fields) { ['Title', 'Author username', 'state'] }
  let(:invalid_fields) { ['Title', 'Author Username', 'State', 'Invalid Field', 'Other Field'] }
  let(:data) do
    {
      'Requirement ID' => '1',
      'Title' => 'foo',
      'Description' => 'bar',
      'Author' => 'root',
      'Author Username' => 'admin',
      'Created At (UTC)' => '2023-02-01 15:16:35',
      'State' => 'opened',
      'State Updated At (UTC)' => '2023-02-01 15:16:35'
    }
  end

  describe '#execute' do
    it 'returns a hash with selected fields only' do
      result = described_class.new(selected_fields, data).execute

      expect(result).to be_a(Hash)
      expect(result.keys).to match_array(selected_fields.map(&:titleize))
    end

    context 'when the fields collection is empty' do
      it 'returns a hash with all fields' do
        result = described_class.new([], data).execute

        expect(result).to be_a(Hash)
        expect(result.keys).to match_array(data.keys)
      end
    end

    context 'when fields collection includes invalid fields' do
      it 'returns a hash with valid selected fields only' do
        result = described_class.new(invalid_fields, data).execute

        expect(result).to be_a(Hash)
        expect(result.keys).to eq(selected_fields.map(&:titleize))
      end
    end
  end

  describe '#invalid_fields' do
    it 'returns an array containing invalid fields' do
      result = described_class.new(invalid_fields, data).invalid_fields

      expect(result).to match_array(['Invalid Field', 'Other Field'])
    end
  end
end


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

module ExportCsv
  class BaseService
    # Target attachment size before base64 encoding
    TARGET_FILESIZE = 15.megabytes

    def initialize(relation, resource_parent, fields = [])
      @objects = relation
      @resource_parent = resource_parent
      @fields = fields
    end

    def csv_data
      csv_builder.render(TARGET_FILESIZE)
    end

    def email(user)
      raise NotImplementedError
    end

    def invalid_fields
      ::ExportCsv::MapExportFieldsService.new(fields, header_to_value_hash).invalid_fields
    end

    private

    attr_reader :resource_parent, :objects, :fields

    # rubocop: disable CodeReuse/ActiveRecord
    def csv_builder
      @csv_builder ||= begin
        data_hash = MapExportFieldsService.new(fields, header_to_value_hash).execute

        if preload_associations_in_batches?
          CsvBuilder.new(objects, data_hash, associations_to_preload)
        else
          CsvBuilder.new(objects.preload(associations_to_preload), data_hash, [])
        end
      end
    end
    # rubocop: enable CodeReuse/ActiveRecord

    def associations_to_preload
      []
    end

    def header_to_value_hash
      raise NotImplementedError
    end

    def preload_associations_in_batches?
      false
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe ExportCsv::BaseService, feature_category: :importers do
  let_it_be(:issue) { create(:issue) }
  let_it_be(:relation) { Issue.all }
  let_it_be(:resource_parent) { issue.project }

  subject { described_class.new(relation, resource_parent) }

  describe '#email' do
    it 'raises NotImplementedError' do
      user = create(:user)

      expect { subject.email(user) }.to raise_error(NotImplementedError)
    end
  end

  describe '#header_to_value_hash' do
    it 'raises NotImplementedError' do
      expect { subject.send(:header_to_value_hash) }.to raise_error(NotImplementedError)
    end
  end

  describe '#associations_to_preload' do
    it 'return []' do
      expect(subject.send(:associations_to_preload)).to eq([])
    end
  end
end


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

module MergeRequests
  class PushedBranchesService < MergeRequests::BaseService
    include ::Gitlab::Utils::StrongMemoize

    # Skip moving this logic into models since it's too specific
    # rubocop: disable CodeReuse/ActiveRecord
    def execute
      return [] if branch_names.blank?

      source_branches = project.source_of_merge_requests.open_and_closed
        .from_source_branches(branch_names).pluck(:source_branch)

      target_branches = project.merge_requests.opened
        .by_target_branch(branch_names).distinct.pluck(:target_branch)

      source_branches.concat(target_branches).to_set
    end
    # rubocop: enable CodeReuse/ActiveRecord

    private

    def branch_names
      strong_memoize(:branch_names) do
        params[:changes].map do |change|
          Gitlab::Git.branch_name(change[:ref])
        end.compact
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe MergeRequests::PushedBranchesService, feature_category: :source_code_management do
  let(:project) { create(:project) }
  let!(:service) { described_class.new(project: project, current_user: nil, params: { changes: pushed_branches }) }

  context 'when branches pushed' do
    let(:pushed_branches) do
      %w[branch1 branch2 closed-branch1 closed-branch2 extra1 extra2].map do |branch|
        { ref: "refs/heads/#{branch}" }
      end
    end

    it 'returns only branches which have a open and closed merge request' do
      create(:merge_request, source_branch: 'branch1', source_project: project)
      create(:merge_request, source_branch: 'branch2', source_project: project)
      create(:merge_request, target_branch: 'branch2', source_project: project)
      create(:merge_request, :closed, target_branch: 'closed-branch1', source_project: project)
      create(:merge_request, :closed, source_branch: 'closed-branch2', source_project: project)
      create(:merge_request, source_branch: 'extra1')

      expect(service.execute).to contain_exactly(
        'branch1',
        'branch2',
        'closed-branch2'
      )
    end
  end

  context 'when tags pushed' do
    let(:pushed_branches) do
      %w[v10.0.0 v11.0.2 v12.1.0].map do |branch|
        { ref: "refs/tags/#{branch}" }
      end
    end

    it 'returns empty result without any SQL query performed' do
      control_count = ActiveRecord::QueryRecorder.new do
        expect(service.execute).to be_empty
      end.count

      expect(control_count).to be_zero
    end
  end
end


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

module MergeRequests
  class RebaseService < MergeRequests::BaseService
    REBASE_ERROR = 'Rebase failed: Rebase locally, resolve all conflicts, then push the branch.'

    attr_reader :merge_request, :rebase_error

    def validate(merge_request)
      return error_response(_('Source branch does not exist')) unless
        merge_request.source_branch_exists?

      return error_response(_('Cannot push to source branch')) unless
          user_access.can_push_to_branch?(merge_request.source_branch)

      return error_response(_('Source branch is protected from force push')) unless
          merge_request.permits_force_push?

      ServiceResponse.success
    end

    def execute(merge_request, skip_ci: false)
      @merge_request = merge_request
      @skip_ci = skip_ci

      if rebase
        success
      else
        error(rebase_error)
      end
    end

    def rebase
      repository.rebase(current_user, merge_request, skip_ci: @skip_ci)

      true
    rescue StandardError => e
      set_rebase_error(e)
      log_error(exception: e, message: rebase_error, save_message_on_model: true)

      false
    ensure
      merge_request.update_column(:rebase_jid, nil)
    end

    private

    def set_rebase_error(exception)
      @rebase_error =
        if exception.is_a?(Gitlab::Git::PreReceiveError)
          "The rebase pre-receive hook failed: #{exception.message}."
        else
          REBASE_ERROR
        end
    end

    def user_access
      Gitlab::UserAccess.new(current_user, container: project)
    end

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

::MergeRequests::RebaseService.prepend_mod

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe MergeRequests::RebaseService, feature_category: :source_code_management do
  include ProjectForksHelper

  let(:user) { create(:user) }
  let(:rebase_jid) { 'fake-rebase-jid' }
  let(:merge_request) do
    create(
      :merge_request,
      source_branch: 'feature_conflict',
      target_branch: 'master',
      rebase_jid: rebase_jid
    )
  end

  let(:project) { merge_request.project }
  let(:repository) { project.repository.raw }
  let(:skip_ci) { false }

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

  before do
    project.add_maintainer(user)
  end

  describe '#validate' do
    subject { service.validate(merge_request) }

    it { is_expected.to be_success }

    context 'when source branch does not exist' do
      before do
        merge_request.update!(source_branch: 'does_not_exist')
      end

      it 'returns an error' do
        is_expected.to be_error
        expect(subject.message).to eq('Source branch does not exist')
      end
    end

    context 'when user has no permissions to rebase' do
      before do
        project.add_guest(user)
      end

      it 'returns an error' do
        is_expected.to be_error
        expect(subject.message).to eq('Cannot push to source branch')
      end
    end

    context 'when branch is protected' do
      before do
        create(:protected_branch, project: project, name: merge_request.source_branch, allow_force_push: false)
      end

      it 'returns an error' do
        is_expected.to be_error
        expect(subject.message).to eq('Source branch is protected from force push')
      end
    end
  end

  describe '#execute' do
    shared_examples 'sequence of failure and success' do
      it 'properly clears the error message' do
        allow(repository).to receive(:gitaly_operation_client).and_raise('Something went wrong')

        service.execute(merge_request)
        merge_request.reload

        expect(merge_request.reload.merge_error).to eq(described_class::REBASE_ERROR)
        expect(merge_request.rebase_jid).to eq(nil)

        allow(repository).to receive(:gitaly_operation_client).and_call_original
        merge_request.update!(rebase_jid: rebase_jid)

        service.execute(merge_request)
        merge_request.reload

        expect(merge_request.merge_error).to eq(nil)
        expect(merge_request.rebase_jid).to eq(nil)
      end
    end

    it_behaves_like 'sequence of failure and success'

    context 'when unexpected error occurs' do
      let(:exception) { RuntimeError.new('Something went wrong') }
      let(:merge_request_ref) { merge_request.to_reference(full: true) }

      before do
        allow(repository).to receive(:gitaly_operation_client).and_raise(exception)
      end

      it 'saves a generic error message' do
        service.execute(merge_request)

        expect(merge_request.reload.merge_error).to eq(described_class::REBASE_ERROR)
      end

      it 'returns an error' do
        expect(service.execute(merge_request)).to match(
          status: :error, message: described_class::REBASE_ERROR
        )
      end

      it 'logs the error' do
        expect(service).to receive(:log_error).with(exception: exception, message: described_class::REBASE_ERROR, save_message_on_model: true).and_call_original
        expect(Gitlab::ErrorTracking).to receive(:track_exception).with(exception,
          {
            class: described_class.to_s,
            merge_request: merge_request_ref,
            merge_request_id: merge_request.id,
            message: described_class::REBASE_ERROR,
            save_message_on_model: true
          }).and_call_original

        service.execute(merge_request)
      end
    end

    context 'with a pre-receive failure' do
      let(:pre_receive_error) { "Commit message does not follow the pattern 'ACME'" }
      let(:merge_error) { "The rebase pre-receive hook failed: #{pre_receive_error}." }

      before do
        allow(repository).to receive(:gitaly_operation_client).and_raise(Gitlab::Git::PreReceiveError, "GitLab: #{pre_receive_error}")
      end

      it 'saves a specific message' do
        subject.execute(merge_request)

        expect(merge_request.reload.merge_error).to eq merge_error
      end

      it 'returns an error' do
        expect(service.execute(merge_request)).to match(
          status: :error,
          message: merge_error)
      end
    end

    context 'with git command failure' do
      before do
        allow(repository).to receive(:gitaly_operation_client).and_raise(Gitlab::Git::Repository::GitError, 'Something went wrong')
      end

      it 'saves a generic error message' do
        subject.execute(merge_request)

        expect(merge_request.reload.merge_error).to eq described_class::REBASE_ERROR
      end

      it 'returns an error' do
        expect(service.execute(merge_request)).to match(
          status: :error, message: described_class::REBASE_ERROR
        )
      end
    end

    context 'valid params' do
      shared_examples_for 'a service that can execute a successful rebase' do
        before do
          service.execute(merge_request, skip_ci: skip_ci)
        end

        it 'rebases source branch' do
          parent_sha = merge_request.source_project.repository.commit(merge_request.source_branch).parents.first.sha
          target_branch_sha = merge_request.target_project.repository.commit(merge_request.target_branch).sha
          expect(parent_sha).to eq(target_branch_sha)
        end

        it 'records the new SHA on the merge request' do
          head_sha = merge_request.source_project.repository.commit(merge_request.source_branch).sha
          expect(merge_request.reload.rebase_commit_sha).to eq(head_sha)
        end

        it 'logs correct author and committer' do
          head_commit = merge_request.source_project.repository.commit(merge_request.source_branch)

          expect(head_commit.author_email).to eq('dmitriy.zaporozhets@gmail.com')
          expect(head_commit.author_name).to eq('Dmitriy Zaporozhets')
          expect(head_commit.committer_email).to eq(user.email)
          expect(head_commit.committer_name).to eq(user.name)
        end
      end

      it_behaves_like 'a service that can execute a successful rebase'

      it 'clears rebase_jid' do
        expect { service.execute(merge_request) }
          .to change(merge_request, :rebase_jid)
          .from(rebase_jid)
          .to(nil)
      end

      context 'when skip_ci flag is set' do
        let(:skip_ci) { true }

        it_behaves_like 'a service that can execute a successful rebase'
      end

      context 'fork' do
        describe 'successful fork rebase' do
          let(:forked_project) do
            fork_project(project, user, repository: true)
          end

          let(:merge_request_from_fork) do
            forked_project.repository.create_file(
              user,
              'new-file-to-target',
              '',
              message: 'Add new file to target',
              branch_name: 'master')

            create(
              :merge_request,
              source_branch: 'master', source_project: forked_project,
              target_branch: 'master', target_project: project
            )
          end

          it 'rebases source branch', :sidekiq_might_not_need_inline do
            parent_sha = forked_project.repository.commit(merge_request_from_fork.source_branch).parents.first.sha
            target_branch_sha = project.repository.commit(merge_request_from_fork.target_branch).sha
            expect(parent_sha).to eq(target_branch_sha)
          end
        end
      end
    end
  end
end


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

module MergeRequests
  class ExportCsvService < ExportCsv::BaseService
    include Gitlab::Routing.url_helpers
    include GitlabRoutingHelper

    def email(user)
      Notify.merge_requests_csv_email(user, resource_parent, csv_data, csv_builder.status).deliver_now
    end

    private

    def header_to_value_hash
      {
        'Title' => 'title',
        'Description' => 'description',
        'MR IID' => 'iid',
        'URL' => -> (merge_request) { merge_request_url(merge_request) },
        'State' => 'state',
        'Source Branch' => 'source_branch',
        'Target Branch' => 'target_branch',
        'Source Project ID' => 'source_project_id',
        'Target Project ID' => 'target_project_id',
        'Author' => -> (merge_request) { merge_request.author.name },
        'Author Username' => -> (merge_request) { merge_request.author.username },
        'Assignees' => -> (merge_request) { merge_request.assignees.map(&:name).join(', ') },
        'Assignee Usernames' => -> (merge_request) { merge_request.assignees.map(&:username).join(', ') },
        'Approvers' => -> (merge_request) { merge_request.approved_by_users.map(&:name).join(', ') },
        'Approver Usernames' => -> (merge_request) { merge_request.approved_by_users.map(&:username).join(', ') },
        'Merged User' => -> (merge_request) { merge_request.metrics&.merged_by&.name.to_s },
        'Merged Username' => -> (merge_request) { merge_request.metrics&.merged_by&.username.to_s },
        'Milestone ID' => -> (merge_request) { merge_request&.milestone&.id || '' },
        'Created At (UTC)' => -> (merge_request) { merge_request.created_at.utc },
        'Updated At (UTC)' => -> (merge_request) { merge_request.updated_at.utc }
      }
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe MergeRequests::ExportCsvService, feature_category: :importers do
  let_it_be(:merge_request) { create(:merge_request) }

  let(:csv) { CSV.parse(subject.csv_data, headers: true).first }

  subject { described_class.new(MergeRequest.where(id: merge_request.id), merge_request.project) }

  describe 'csv_data' do
    it 'contains the correct information', :aggregate_failures do
      expect(csv['MR IID']).to eq(merge_request.iid.to_s)
      expect(csv['Title']).to eq(merge_request.title)
      expect(csv['State']).to eq(merge_request.state)
      expect(csv['Description']).to eq(merge_request.description)
      expect(csv['Source Branch']).to eq(merge_request.source_branch)
      expect(csv['Target Branch']).to eq(merge_request.target_branch)
      expect(csv['Source Project ID']).to eq(merge_request.source_project_id.to_s)
      expect(csv['Target Project ID']).to eq(merge_request.target_project_id.to_s)
      expect(csv['Author']).to eq(merge_request.author.name)
      expect(csv['Author Username']).to eq(merge_request.author.username)
    end

    describe 'assignees' do
      context 'when assigned' do
        let_it_be(:merge_request) { create(:merge_request, assignees: create_list(:user, 2)) }

        it 'contains the names of assignees' do
          expect(csv['Assignees'].split(', ')).to match_array(merge_request.assignees.map(&:name))
        end

        it 'contains the usernames of assignees' do
          expect(csv['Assignee Usernames'].split(', ')).to match_array(merge_request.assignees.map(&:username))
        end
      end

      context 'when not assigned' do
        it 'returns empty strings' do
          expect(csv['Assignees']).to eq('')
          expect(csv['Assignee Usernames']).to eq('')
        end
      end
    end

    describe 'approvers' do
      context 'when approved' do
        let_it_be(:merge_request) { create(:merge_request) }

        let(:approvers) { create_list(:user, 2) }

        before do
          merge_request.approved_by_users = approvers
        end

        it 'contains the names of approvers separated by a comma' do
          expect(csv['Approvers'].split(', ')).to contain_exactly(approvers[0].name, approvers[1].name)
        end

        it 'contains the usernames of approvers separated by a comma' do
          expect(csv['Approver Usernames'].split(', ')).to contain_exactly(approvers[0].username, approvers[1].username)
        end
      end

      context 'when not approved' do
        it 'returns empty strings' do
          expect(csv['Approvers']).to eq('')
          expect(csv['Approver Usernames']).to eq('')
        end
      end
    end

    describe 'merged user' do
      context 'MR is merged' do
        let_it_be(:merge_request) { create(:merge_request, :merged, :with_merged_metrics) }

        it 'is merged' do
          expect(csv['State']).to eq('merged')
        end

        it 'has a merged user' do
          expect(csv['Merged User']).to eq(merge_request.metrics.merged_by.name)
          expect(csv['Merged Username']).to eq(merge_request.metrics.merged_by.username)
        end
      end

      context 'MR is not merged' do
        it 'returns empty strings' do
          expect(csv['Merged User']).to eq('')
          expect(csv['Merged Username']).to eq('')
        end
      end
    end

    describe 'milestone' do
      context 'milestone is assigned' do
        let_it_be(:merge_request) { create(:merge_request) }
        let_it_be(:milestone) { create(:milestone, :active, project: merge_request.project) }

        before do
          merge_request.update!(milestone_id: milestone.id)
        end

        it 'contains the milestone ID' do
          expect(csv['Milestone ID']).to eq(merge_request.milestone.id.to_s)
        end
      end

      context 'no milestone is assigned' do
        it 'returns an empty string' do
          expect(csv['Milestone ID']).to eq('')
        end
      end
    end

    describe '#email' do
      let_it_be(:user) { create(:user) }

      it 'emails csv' do
        expect { subject.email(user) }.to change { ActionMailer::Base.deliveries.count }
      end

      it 'renders with a target filesize' do
        expect_next_instance_of(CsvBuilder) do |csv_builder|
          expect(csv_builder).to receive(:render).with(described_class::TARGET_FILESIZE).once
        end

        subject.email(user)
      end
    end
  end
end


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

module MergeRequests
  class LinkLfsObjectsService < ::BaseProjectService
    def execute(merge_request, oldrev: merge_request.diff_base_sha, newrev: merge_request.diff_head_sha)
      return if merge_request.source_project == project
      return if no_changes?(oldrev, newrev)

      new_lfs_oids = lfs_oids(merge_request.source_project.repository, oldrev, newrev)

      return if new_lfs_oids.empty?

      Projects::LfsPointers::LfsLinkService
        .new(project)
        .execute(new_lfs_oids)
    end

    private

    def no_changes?(oldrev, newrev)
      oldrev == newrev
    end

    def lfs_oids(source_repository, oldrev, newrev)
      Gitlab::Git::LfsChanges
        .new(source_repository, newrev)
        .new_pointers(not_in: [oldrev])
        .map(&:lfs_oid)
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe MergeRequests::LinkLfsObjectsService, :sidekiq_inline, feature_category: :code_review_workflow do
  include ProjectForksHelper
  include RepoHelpers

  let(:target_project) { create(:project, :public, :repository) }

  let(:merge_request) do
    create(
      :merge_request,
      target_project: target_project,
      target_branch: 'lfs',
      source_project: source_project,
      source_branch: 'link-lfs-objects'
    )
  end

  subject { described_class.new(project: target_project) }

  shared_examples_for 'linking LFS objects' do
    context 'when source project is the same as target project' do
      let(:source_project) { target_project }

      it 'does not call Projects::LfsPointers::LfsLinkService#execute' do
        expect(Projects::LfsPointers::LfsLinkService).not_to receive(:new)

        execute
      end
    end

    context 'when source project is different from target project' do
      let(:user) { create(:user) }
      let(:source_project) { fork_project(target_project, user, namespace: user.namespace, repository: true) }

      before do
        create_branch(source_project, 'link-lfs-objects', 'lfs')
      end

      context 'and there are changes' do
        before do
          allow(source_project).to receive(:lfs_enabled?).and_return(true)
        end

        context 'and there are LFS objects added' do
          before do
            create_file_in_repo(source_project, 'link-lfs-objects', 'link-lfs-objects', 'one.lfs', 'One')
            create_file_in_repo(source_project, 'link-lfs-objects', 'link-lfs-objects', 'two.lfs', 'Two')
          end

          it 'calls Projects::LfsPointers::LfsLinkService#execute with OIDs of LFS objects in merge request' do
            expect_next_instance_of(Projects::LfsPointers::LfsLinkService) do |service|
              expect(service).to receive(:execute).with(
                %w[
                  8b12507783d5becacbf2ebe5b01a60024d8728a8f86dcc818bce699e8b3320bc
                  94a72c074cfe574742c9e99e863322f73feff82981d065ff65a0308f44f19f62
                ])
            end

            execute
          end
        end

        context 'but there are no LFS objects added' do
          before do
            create_file_in_repo(source_project, 'link-lfs-objects', 'link-lfs-objects', 'one.txt', 'One')
          end

          it 'does not call Projects::LfsPointers::LfsLinkService#execute' do
            expect(Projects::LfsPointers::LfsLinkService).not_to receive(:new)

            execute
          end
        end
      end

      context 'and there are no changes' do
        it 'does not call Projects::LfsPointers::LfsLinkService#execute' do
          expect(Projects::LfsPointers::LfsLinkService).not_to receive(:new)

          execute
        end
      end
    end
  end

  context 'when no oldrev and newrev passed' do
    let(:execute) { subject.execute(merge_request) }

    it_behaves_like 'linking LFS objects'
  end

  context 'when oldrev and newrev are passed' do
    let(:execute) { subject.execute(merge_request, oldrev: merge_request.diff_base_sha, newrev: merge_request.diff_head_sha) }

    it_behaves_like 'linking LFS objects'
  end

  def create_branch(project, new_name, branch_name)
    ::Branches::CreateService.new(project, user).execute(new_name, branch_name)
  end
end


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

module MergeRequests
  class MergeabilityCheckService < ::BaseService
    include Gitlab::Utils::StrongMemoize
    include Gitlab::ExclusiveLeaseHelpers

    delegate :project, to: :@merge_request
    delegate :repository, to: :project

    def initialize(merge_request)
      @merge_request = merge_request
    end

    def async_execute
      return service_error if service_error

      merge_request.mark_as_checking
      MergeRequestMergeabilityCheckWorker.perform_async(merge_request.id)
    end

    # Updates the MR merge_status. Whenever it switches to a can_be_merged state,
    # the merge-ref is refreshed.
    #
    # recheck - When given, it'll enforce a merge-ref refresh if the current merge_status is
    # can_be_merged or cannot_be_merged and merge-ref is outdated.
    # Given MergeRequests::RefreshService is called async, it might happen that the target
    # branch gets updated, but the MergeRequest#merge_status lags behind. So in scenarios
    # where we need the current state of the merge ref in repository, the `recheck`
    # argument is required.
    #
    # retry_lease - Concurrent calls wait for at least 10 seconds until the
    # lease is granted (other process finishes running). Returns an error
    # ServiceResponse if the lease is not granted during this time.
    #
    # Returns a ServiceResponse indicating merge_status is/became can_be_merged
    # and the merge-ref is synced. Success in case of being/becoming mergeable,
    # error otherwise.
    def execute(recheck: false, retry_lease: true)
      return service_error if service_error

      in_write_lock(retry_lease: retry_lease) do |retried|
        # When multiple calls are waiting for the same lock (retry_lease),
        # it's possible that when granted, the MR status was already updated for
        # that object, therefore we reset if there was a lease retry.
        merge_request.reset if retried

        check_mergeability(recheck)
      end
    rescue FailedToObtainLockError => error
      ServiceResponse.error(message: error.message)
    end

    private

    attr_reader :merge_request

    def check_mergeability(recheck)
      recheck! if recheck
      update_merge_status

      unless merge_request.can_be_merged?
        return ServiceResponse.error(message: 'Merge request is not mergeable')
      end

      unless payload.fetch(:merge_ref_head)
        return ServiceResponse.error(message: 'Merge ref cannot be updated')
      end

      ServiceResponse.success(payload: payload)
    end

    # It's possible for this service to send concurrent requests to Gitaly in order
    # to "git update-ref" the same ref. Therefore we handle a light exclusive
    # lease here.
    #
    def in_write_lock(retry_lease:, &block)
      lease_key = "mergeability_check:#{merge_request.id}"

      lease_opts = {
        ttl: 1.minute,
        retries: retry_lease ? 10 : 0,
        sleep_sec: retry_lease ? 1.second : 0
      }

      in_lock(lease_key, **lease_opts, &block)
    end

    def payload
      strong_memoize(:payload) do
        {
          merge_ref_head: merge_ref_head_payload
        }
      end
    end

    def merge_ref_head_payload
      commit = merge_request.merge_ref_head

      return unless commit

      target_id, source_id = commit.parent_ids

      {
        commit_id: commit.id,
        source_id: source_id,
        target_id: target_id
      }
    end

    def update_merge_status
      return unless merge_request.recheck_merge_status?
      return merge_request.mark_as_unmergeable if merge_request.broken?

      merge_to_ref_success = merge_to_ref

      reload_merge_head_diff
      update_diff_discussion_positions! if merge_to_ref_success

      if merge_to_ref_success && can_git_merge?
        merge_request.mark_as_mergeable
      else
        merge_request.mark_as_unmergeable
      end
    end

    def reload_merge_head_diff
      MergeRequests::ReloadMergeHeadDiffService.new(merge_request).execute
    end

    def update_diff_discussion_positions!
      Discussions::CaptureDiffNotePositionsService.new(merge_request).execute
    end

    def recheck!
      if !merge_request.recheck_merge_status? && outdated_merge_ref?
        merge_request.mark_as_unchecked
      end
    end

    # Checks if the existing merge-ref is synced with the target branch.
    #
    # Returns true if the merge-ref does not exists or is out of sync.
    def outdated_merge_ref?
      return false unless merge_request.open?

      return true unless ref_head = merge_request.merge_ref_head
      return true unless target_sha = merge_request.target_branch_sha
      return true unless source_sha = merge_request.source_branch_sha

      ref_head.parent_ids != [target_sha, source_sha]
    end

    def can_git_merge?
      repository.can_be_merged?(merge_request.diff_head_sha, merge_request.target_branch)
    end

    def merge_to_ref
      result = MergeRequests::MergeToRefService.new(project: project, current_user: merge_request.author, params: {}).execute(merge_request)

      result[:status] == :success
    end

    def service_error
      strong_memoize(:service_error) do
        if !merge_request
          ServiceResponse.error(message: 'Invalid argument')
        elsif Gitlab::Database.read_only?
          ServiceResponse.error(message: 'Unsupported operation')
        end
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe MergeRequests::MergeabilityCheckService, :clean_gitlab_redis_shared_state, feature_category: :code_review_workflow do
  shared_examples_for 'unmergeable merge request' do
    it 'updates or keeps merge status as cannot_be_merged' do
      subject

      expect(merge_request.merge_status).to eq('cannot_be_merged')
    end

    it 'does not change the merge ref HEAD' do
      merge_ref_head = merge_request.merge_ref_head

      subject

      expect(merge_request.reload.merge_ref_head).to eq merge_ref_head
    end

    it 'returns ServiceResponse.error' do
      result = subject

      expect(result).to be_a(ServiceResponse)
      expect(result).to be_error
    end
  end

  shared_examples_for 'mergeable merge request' do
    it 'updates or keeps merge status as can_be_merged' do
      subject

      expect(merge_request.merge_status).to eq('can_be_merged')
    end

    it 'reloads merge head diff' do
      expect_next_instance_of(MergeRequests::ReloadMergeHeadDiffService) do |service|
        expect(service).to receive(:execute)
      end

      subject
    end

    it 'update diff discussion positions' do
      expect_next_instance_of(Discussions::CaptureDiffNotePositionsService) do |service|
        expect(service).to receive(:execute)
      end

      subject
    end

    it 'updates the merge ref' do
      expect { subject }.to change(merge_request, :merge_ref_head).from(nil)
    end

    it 'returns ServiceResponse.success' do
      result = subject

      expect(result).to be_a(ServiceResponse)
      expect(result).to be_success
    end

    it 'ServiceResponse has merge_ref_head payload' do
      result = subject

      expect(result.payload.keys).to contain_exactly(:merge_ref_head)
      expect(result.payload[:merge_ref_head].keys)
        .to contain_exactly(:commit_id, :target_id, :source_id)
    end
  end

  let(:project) { create(:project, :repository) }
  let(:merge_request) { create(:merge_request, merge_status: :unchecked, source_project: project, target_project: project) }

  describe '#async_execute' do
    it 'updates merge status to checking' do
      described_class.new(merge_request).async_execute

      expect(merge_request).to be_checking
    end

    it 'enqueues MergeRequestMergeabilityCheckWorker' do
      expect(MergeRequestMergeabilityCheckWorker).to receive(:perform_async)

      described_class.new(merge_request).async_execute
    end

    context 'when read-only DB' do
      before do
        allow(Gitlab::Database).to receive(:read_only?) { true }
      end

      it 'does not enqueue MergeRequestMergeabilityCheckWorker' do
        expect(MergeRequestMergeabilityCheckWorker).not_to receive(:perform_async)

        described_class.new(merge_request).async_execute
      end
    end
  end

  describe '#execute' do
    let(:repo) { project.repository }

    subject { described_class.new(merge_request).execute }

    def execute_within_threads(amount:, retry_lease: true)
      threads = []

      amount.times do
        # Let's use a different object for each thread to get closer
        # to a real world scenario.
        mr = MergeRequest.find(merge_request.id)

        threads << Thread.new do
          described_class.new(mr).execute(retry_lease: retry_lease)
        end
      end

      threads.each(&:join)
      threads
    end

    before do
      project.add_developer(merge_request.author)
    end

    it_behaves_like 'mergeable merge request'

    context 'when concurrent calls' do
      it 'waits first lock and returns "cached" result in subsequent calls' do
        threads = execute_within_threads(amount: 3)
        results = threads.map { |t| t.value.status }

        expect(results).to contain_exactly(:success, :success, :success)
      end

      it 'writes the merge-ref once' do
        service = instance_double(MergeRequests::MergeToRefService)

        expect(MergeRequests::MergeToRefService).to receive(:new).once { service }
        expect(service).to receive(:execute).once.and_return(success: true)

        execute_within_threads(amount: 3)
      end

      it 'resets one merge request upon execution' do
        expect_next_instance_of(MergeRequests::ReloadMergeHeadDiffService) do |svc|
          expect(svc).to receive(:execute).and_return(status: :success)
        end

        expect_any_instance_of(MergeRequest).to receive(:reset).once.and_call_original

        execute_within_threads(amount: 2)
      end

      context 'when retry_lease flag is false' do
        it 'the first call succeeds, subsequent concurrent calls get a lock error response' do
          threads = execute_within_threads(amount: 3, retry_lease: false)
          results = threads.map { |t| [t.value.status, t.value.message] }

          expect(results).to contain_exactly(
            [:error, 'Failed to obtain a lock'],
            [:error, 'Failed to obtain a lock'],
            [:success, nil]
          )
        end
      end
    end

    context 'when broken' do
      before do
        expect(merge_request).to receive(:broken?) { true }
      end

      it_behaves_like 'unmergeable merge request'

      it 'returns ServiceResponse.error' do
        result = subject

        expect(result).to be_a(ServiceResponse)
        expect(result.error?).to be(true)
        expect(result.message).to eq('Merge request is not mergeable')
      end
    end

    context 'when it cannot be merged on git' do
      let(:merge_request) do
        create(
          :merge_request,
          merge_status: :unchecked,
          source_branch: 'conflict-resolvable',
          source_project: project,
          target_branch: 'conflict-start'
        )
      end

      it 'returns ServiceResponse.error and keeps merge status as cannot_be_merged' do
        result = subject

        expect(merge_request.merge_status).to eq('cannot_be_merged')
        expect(result).to be_a(ServiceResponse)
        expect(result.error?).to be(true)
        expect(result.message).to eq('Merge request is not mergeable')
      end
    end

    context 'when MR cannot be merged and has no merge ref' do
      before do
        merge_request.mark_as_unmergeable!
      end

      it_behaves_like 'unmergeable merge request'

      it 'returns ServiceResponse.error' do
        result = subject

        expect(result).to be_a(ServiceResponse)
        expect(result.error?).to be(true)
        expect(result.message).to eq('Merge request is not mergeable')
      end
    end

    context 'when MR cannot be merged and has outdated merge ref' do
      before do
        MergeRequests::MergeToRefService.new(project: project, current_user: merge_request.author).execute(merge_request)
        merge_request.mark_as_unmergeable!
      end

      it_behaves_like 'unmergeable merge request'

      it 'returns ServiceResponse.error' do
        result = subject

        expect(result).to be_a(ServiceResponse)
        expect(result.error?).to be(true)
        expect(result.message).to eq('Merge request is not mergeable')
      end
    end

    context 'when merge request is not given' do
      subject { described_class.new(nil).execute }

      it 'returns ServiceResponse.error' do
        result = subject

        expect(result).to be_a(ServiceResponse)
        expect(result.message).to eq('Invalid argument')
      end
    end

    context 'when read-only DB' do
      it 'returns ServiceResponse.error' do
        allow(Gitlab::Database).to receive(:read_only?) { true }

        result = subject

        expect(result).to be_a(ServiceResponse)
        expect(result.message).to eq('Unsupported operation')
      end
    end

    context 'when fails to update the merge-ref' do
      before do
        expect_next_instance_of(MergeRequests::MergeToRefService) do |merge_to_ref|
          expect(merge_to_ref).to receive(:execute).and_return(status: :failed)
        end
      end

      it_behaves_like 'unmergeable merge request'

      it 'reloads merge head diff' do
        expect_next_instance_of(MergeRequests::ReloadMergeHeadDiffService) do |service|
          expect(service).to receive(:execute)
        end

        subject
      end

      it 'returns ServiceResponse.error' do
        result = subject

        expect(result).to be_a(ServiceResponse)
        expect(result.error?).to be(true)
        expect(result.message).to eq('Merge request is not mergeable')
      end
    end

    context 'recheck enforced' do
      subject { described_class.new(merge_request).execute(recheck: true) }

      context 'when MR is marked as mergeable, but repo is not mergeable and MR is not opened' do
        before do
          # Making sure that we don't touch the merge-status after
          # the MR is not opened any longer. Source branch might
          # have been removed, etc.
          allow(merge_request).to receive(:broken?) { true }
          merge_request.mark_as_mergeable!
          merge_request.close!
        end

        it 'returns ServiceResponse.error' do
          result = subject

          expect(result).to be_a(ServiceResponse)
          expect(result.error?).to be(true)
          expect(result.message).to eq('Merge ref cannot be updated')
          expect(result.payload).to be_empty
        end

        it 'does not change the merge status' do
          expect { subject }.not_to change(merge_request, :merge_status).from('can_be_merged')
        end
      end

      context 'when MR is mergeable but merge-ref does not exists' do
        before do
          merge_request.mark_as_mergeable!
        end

        it_behaves_like 'mergeable merge request'
      end

      context 'when MR is mergeable but merge-ref is already updated' do
        before do
          MergeRequests::MergeToRefService.new(project: project, current_user: merge_request.author).execute(merge_request)
          merge_request.mark_as_mergeable!
        end

        it 'returns ServiceResponse.success' do
          result = subject

          expect(result).to be_a(ServiceResponse)
          expect(result).to be_success
          expect(result.payload[:merge_ref_head]).to be_present
        end

        it 'does not recreate the merge-ref' do
          expect(MergeRequests::MergeToRefService).not_to receive(:new)

          subject
        end

        it 'does not reload merge head diff' do
          expect(MergeRequests::ReloadMergeHeadDiffService).not_to receive(:new)

          subject
        end
      end
    end
  end
end


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

module MergeRequests
  class AssignIssuesService < BaseProjectService
    def assignable_issues
      @assignable_issues ||= if current_user == merge_request.author
                               closes_issues.select do |issue|
                                 !issue.is_a?(ExternalIssue) && !issue.assignees.present? && can?(current_user, :admin_issue, issue)
                               end
                             else
                               []
                             end
    end

    def execute
      assignable_issues.each do |issue|
        Issues::UpdateService.new(container: issue.project, current_user: current_user, params: { assignee_ids: [current_user.id] }).execute(issue)
      end

      {
        count: assignable_issues.count
      }
    end

    private

    def merge_request
      params[:merge_request]
    end

    def closes_issues
      @closes_issues ||= params[:closes_issues] || merge_request.closes_issues(current_user)
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe MergeRequests::AssignIssuesService, feature_category: :code_review_workflow do
  let(:user) { create(:user) }
  let(:project) { create(:project, :public, :repository) }
  let(:issue) { create(:issue, project: project) }
  let(:merge_request) { create(:merge_request, :simple, source_project: project, author: user, description: "fixes #{issue.to_reference}") }
  let(:service) { described_class.new(project: project, current_user: user, params: { merge_request: merge_request }) }

  before do
    project.add_developer(user)
  end

  it 'finds unassigned issues fixed in merge request' do
    expect(service.assignable_issues.map(&:id)).to include(issue.id)
  end

  it 'ignores issues the user cannot update assignee on', :sidekiq_inline do
    project.team.truncate

    expect(service.assignable_issues).to be_empty
  end

  it 'ignores issues already assigned to any user' do
    issue.assignees = [create(:user)]

    expect(service.assignable_issues).to be_empty
  end

  it 'ignores all issues unless current_user is merge_request.author' do
    merge_request.update!(author: create(:user))

    expect(service.assignable_issues).to be_empty
  end

  it 'accepts precomputed data for closes_issues' do
    issue2 = create(:issue, project: project)
    service2 = described_class.new(
      project: project,
      current_user: user,
      params: {
        merge_request: merge_request,
        closes_issues: [issue, issue2]
      }
    )

    expect(service2.assignable_issues.count).to eq 2
  end

  it 'assigns these to the merge request owner' do
    expect { service.execute }.to change { issue.assignees.first }.to(user)
  end

  it 'ignores external issues' do
    external_issue = ExternalIssue.new('JIRA-123', project)
    service = described_class.new(
      project: project,
      current_user: user,
      params: {
        merge_request: merge_request,
        closes_issues: [external_issue]
      }
    )

    expect(service.assignable_issues.count).to eq 0
  end
end


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

module MergeRequests
  class ReloadDiffsService
    def initialize(merge_request, current_user)
      @merge_request = merge_request
      @current_user = current_user
    end

    def execute
      old_diff_refs = merge_request.diff_refs
      new_diff = merge_request.create_merge_request_diff

      clear_cache(new_diff)
      update_diff_discussion_positions(old_diff_refs)
    end

    private

    attr_reader :merge_request, :current_user

    def update_diff_discussion_positions(old_diff_refs)
      new_diff_refs = merge_request.diff_refs

      merge_request.update_diff_discussion_positions(
        old_diff_refs: old_diff_refs,
        new_diff_refs: new_diff_refs,
        current_user: current_user
      )
    end

    # rubocop: disable CodeReuse/ActiveRecord
    def clear_cache(new_diff)
      # Remove cache for all diffs on this MR. Do not use the association on the
      # model, as that will interfere with other actions happening when
      # reloading the diff.
      MergeRequestDiff
        .where(merge_request: merge_request)
        .preload(merge_request: :target_project)
        .find_each do |merge_request_diff|
        next if merge_request_diff == new_diff

        cacheable_collection(merge_request_diff).clear_cache
      end
    end
    # rubocop: enable CodeReuse/ActiveRecord

    def cacheable_collection(diff)
      # There are scenarios where we don't need to request Diff Stats.
      # Mainly when clearing / writing diff caches.
      diff.diffs(include_stats: false)
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe MergeRequests::ReloadDiffsService, :use_clean_rails_memory_store_caching,
  feature_category: :code_review_workflow do
  let(:current_user) { create(:user) }
  let(:merge_request) { create(:merge_request) }
  let(:subject) { described_class.new(merge_request, current_user) }

  describe '#execute' do
    it 'creates new merge request diff' do
      expect { subject.execute }.to change { merge_request.merge_request_diffs.count }.by(1)
    end

    it 'calls update_diff_discussion_positions with correct params' do
      old_diff_refs = merge_request.diff_refs
      new_diff = merge_request.create_merge_request_diff
      new_diff_refs = merge_request.diff_refs

      expect(merge_request).to receive(:create_merge_request_diff).and_return(new_diff)
      expect(merge_request).to receive(:update_diff_discussion_positions).with(
        old_diff_refs: old_diff_refs, new_diff_refs: new_diff_refs, current_user: current_user
      )

      subject.execute
    end

    it 'does not change existing merge request diff' do
      expect(merge_request.merge_request_diff).not_to receive(:save_git_content)

      subject.execute
    end

    context 'cache clearing' do
      it 'clears the cache for older diffs on the merge request' do
        expect_next_instance_of(Gitlab::Diff::FileCollection::MergeRequestDiff) do |instance|
          expect(instance).to receive(:clear_cache).and_call_original
        end

        subject.execute
      end

      it 'avoids N+1 queries', :request_store do
        current_user
        merge_request

        control_count = ActiveRecord::QueryRecorder.new do
          subject.execute
        end.count

        expect { subject.execute }.not_to exceed_query_limit(control_count)
      end
    end
  end
end


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

module MergeRequests
  class MigrateExternalDiffsService < ::BaseService
    MAX_JOBS = 1000

    attr_reader :diff

    def self.enqueue!
      ids = MergeRequestDiff.ids_for_external_storage_migration(limit: MAX_JOBS)

      # rubocop:disable Scalability/BulkPerformWithContext
      # https://gitlab.com/gitlab-org/gitlab/issues/202100
      MigrateExternalDiffsWorker.bulk_perform_async(ids.map { |id| [id] })
      # rubocop:enable Scalability/BulkPerformWithContext
    end

    def initialize(merge_request_diff)
      @diff = merge_request_diff
    end

    def execute
      diff.migrate_files_to_external_storage!
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe MergeRequests::MigrateExternalDiffsService, feature_category: :code_review_workflow do
  let(:merge_request) { create(:merge_request) }
  let(:diff) { merge_request.merge_request_diff }

  describe '.enqueue!' do
    around do |example|
      Sidekiq::Testing.fake! { example.run }
    end

    it 'enqueues nothing if external diffs are disabled' do
      expect(diff).not_to be_stored_externally

      expect { described_class.enqueue! }
        .not_to change { MigrateExternalDiffsWorker.jobs.count }
    end

    it 'enqueues eligible in-database diffs if external diffs are enabled' do
      expect(diff).not_to be_stored_externally

      stub_external_diffs_setting(enabled: true)

      expect { described_class.enqueue! }
        .to change { MigrateExternalDiffsWorker.jobs.count }
        .by(1)
    end
  end

  describe '#execute' do
    it 'migrates an in-database diff to the external store' do
      expect(diff).not_to be_stored_externally

      stub_external_diffs_setting(enabled: true)

      described_class.new(diff).execute

      expect(diff).to be_stored_externally
    end
  end
end


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

module MergeRequests
  class UpdateReviewerStateService < MergeRequests::BaseService
    def execute(merge_request, state)
      return error("Invalid permissions") unless can?(current_user, :update_merge_request, merge_request)

      reviewer = merge_request.find_reviewer(current_user)

      if reviewer
        return error("Failed to update reviewer") unless reviewer.update(state: state)

        trigger_merge_request_reviewers_updated(merge_request)

        return success if state != 'requested_changes'

        if merge_request.approved_by?(current_user) && !remove_approval(merge_request)
          return error("Failed to remove approval")
        end

        success
      else
        error("Reviewer not found")
      end
    end

    private

    def remove_approval(merge_request)
      MergeRequests::RemoveApprovalService.new(project: project, current_user: current_user)
        .execute(merge_request)
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe MergeRequests::UpdateReviewerStateService, feature_category: :code_review_workflow do
  let_it_be(:current_user) { create(:user) }
  let_it_be(:merge_request) { create(:merge_request, reviewers: [current_user]) }
  let(:reviewer) { merge_request.merge_request_reviewers.find_by(user_id: current_user.id) }
  let(:project) { merge_request.project }
  let(:service) { described_class.new(project: project, current_user: current_user) }
  let(:state) { 'requested_changes' }
  let(:result) { service.execute(merge_request, state) }

  before do
    project.add_developer(current_user)
  end

  describe '#execute' do
    shared_examples_for 'failed service execution' do
      it 'returns an error' do
        expect(result[:status]).to eq :error
      end

      it_behaves_like 'does not trigger GraphQL subscription mergeRequestReviewersUpdated' do
        let(:action) { result }
      end
    end

    describe 'invalid permissions' do
      let(:service) { described_class.new(project: project, current_user: create(:user)) }

      it_behaves_like 'failed service execution'
    end

    describe 'reviewer exists' do
      it 'returns success' do
        expect(result[:status]).to eq :success
      end

      it 'updates reviewers state' do
        expect(result[:status]).to eq :success
        expect(reviewer.state).to eq 'requested_changes'
      end

      it 'does not call MergeRequests::RemoveApprovalService' do
        expect(MergeRequests::RemoveApprovalService).not_to receive(:new)

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

      it_behaves_like 'triggers GraphQL subscription mergeRequestReviewersUpdated' do
        let(:action) { result }
      end

      context 'when reviewer has approved' do
        before do
          create(:approval, user: current_user, merge_request: merge_request)
        end

        it 'removes approval when state is requested_changes' do
          expect_next_instance_of(
            MergeRequests::RemoveApprovalService,
            project: project, current_user: current_user
          ) do |service|
            expect(service).to receive(:execute).with(merge_request).and_return({ success: true })
          end

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

        it 'renders error when remove approval service fails' do
          expect_next_instance_of(
            MergeRequests::RemoveApprovalService,
            project: project, current_user: current_user
          ) do |service|
            expect(service).to receive(:execute).with(merge_request).and_return(nil)
          end

          expect(result[:status]).to eq :error
          expect(result[:message]).to eq "Failed to remove approval"
        end
      end
    end
  end
end


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

module MergeRequests
  class RetargetChainService < MergeRequests::BaseService
    MAX_RETARGET_MERGE_REQUESTS = 4

    def execute(merge_request)
      # we can only retarget MRs that are targeting the same project
      return unless merge_request.for_same_project? && merge_request.merged?

      # find another merge requests that
      # - as a target have a current source project and branch
      other_merge_requests = merge_request.source_project
        .merge_requests
        .opened
        .by_target_branch(merge_request.source_branch)
        .preload_source_project
        .limit(MAX_RETARGET_MERGE_REQUESTS)

      other_merge_requests.find_each do |other_merge_request|
        # Update only MRs on projects that we have access to
        next unless can?(current_user, :update_merge_request, other_merge_request.source_project)

        ::MergeRequests::UpdateService.new(
          project: other_merge_request.source_project,
          current_user: current_user,
          params: {
            target_branch: merge_request.target_branch,
            target_branch_was_deleted: true
          }
        ).execute(other_merge_request)
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe MergeRequests::RetargetChainService, feature_category: :code_review_workflow do
  include ProjectForksHelper

  let_it_be(:user) { create(:user) }
  let_it_be(:merge_request, reload: true) { create(:merge_request, assignees: [user]) }
  let_it_be(:project) { merge_request.project }

  subject { described_class.new(project: project, current_user: user).execute(merge_request) }

  before do
    project.add_maintainer(user)
  end

  describe '#execute' do
    context 'when there is another MR' do
      let!(:another_merge_request) do
        create(:merge_request,
          source_project: source_project,
          source_branch: 'my-awesome-feature',
          target_project: merge_request.source_project,
          target_branch: merge_request.source_branch
        )
      end

      shared_examples 'does not retarget merge request' do
        it 'another merge request is unchanged' do
          expect { subject }.not_to change { another_merge_request.reload.target_branch }
            .from(merge_request.source_branch)
        end
      end

      shared_examples 'retargets merge request' do
        it 'another merge request is retargeted' do
          expect(SystemNoteService)
            .to receive(:change_branch).once
            .with(another_merge_request, another_merge_request.project, user,
              'target', 'delete',
              merge_request.source_branch, merge_request.target_branch)

          expect { subject }.to change { another_merge_request.reload.target_branch }
            .from(merge_request.source_branch)
            .to(merge_request.target_branch)
        end
      end

      context 'in the same project' do
        let(:source_project) { project }

        context 'and current is merged' do
          before do
            merge_request.mark_as_merged
          end

          it_behaves_like 'retargets merge request'
        end

        context 'and current is closed' do
          before do
            merge_request.close
          end

          it_behaves_like 'does not retarget merge request'
        end

        context 'and another is closed' do
          before do
            another_merge_request.close
          end

          it_behaves_like 'does not retarget merge request'
        end

        context 'and another is merged' do
          before do
            another_merge_request.mark_as_merged
          end

          it_behaves_like 'does not retarget merge request'
        end
      end

      context 'in forked project' do
        let!(:source_project) { fork_project(project) }

        context 'when user has access to source project' do
          before do
            source_project.add_developer(user)
            merge_request.mark_as_merged
          end

          it_behaves_like 'retargets merge request'
        end

        context 'when user does not have access to source project' do
          it_behaves_like 'does not retarget merge request'
        end
      end

      context 'and current and another MR is from a fork' do
        let(:project) { create(:project) }
        let(:source_project) { fork_project(project) }

        let(:merge_request) do
          create(:merge_request,
            source_project: source_project,
            target_project: project
          )
        end

        before do
          source_project.add_developer(user)
        end

        it_behaves_like 'does not retarget merge request'
      end
    end

    context 'when many merge requests are to be retargeted' do
      let!(:many_merge_requests) do
        create_list(:merge_request, 10, :unique_branches,
          source_project: merge_request.source_project,
          target_project: merge_request.source_project,
          target_branch: merge_request.source_branch
        )
      end

      before do
        merge_request.mark_as_merged
      end

      it 'retargets only 4 of them' do
        subject

        expect(many_merge_requests.each(&:reload).pluck(:target_branch).tally)
          .to eq(
            merge_request.source_branch => 6,
            merge_request.target_branch => 4
          )
      end
    end
  end
end


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

module MergeRequests
  class CleanupRefsService
    include BaseServiceUtility

    TIME_THRESHOLD = 14.days

    attr_reader :merge_request

    def self.schedule(merge_request)
      merge_request.create_cleanup_schedule(scheduled_at: TIME_THRESHOLD.from_now)
    end

    def initialize(merge_request)
      @merge_request = merge_request
      @repository = merge_request.project.repository
      @ref_path = merge_request.ref_path
      @ref_head_sha = @repository.commit(merge_request.ref_path)&.id
      @merge_ref_sha = merge_request.merge_ref_head&.id
    end

    def execute
      return error("Merge request is not scheduled to be cleaned up yet.") unless scheduled?
      return error("Merge request has not been closed nor merged for #{TIME_THRESHOLD.inspect}.") unless eligible?

      # Ensure that commit shas of refs are kept around so we won't lose them when GC runs.
      keep_around

      return error('Failed to create keep around refs.') unless kept_around?
      return error('Failed to cache merge ref sha.') unless cache_merge_ref_sha

      delete_refs if repository.exists?

      return error('Failed to update schedule.') unless update_schedule

      success
    rescue Gitlab::Git::Repository::GitError, Gitlab::Git::CommandError => e
      error(e.message)
    end

    private

    attr_reader :repository, :ref_path, :ref_head_sha, :merge_ref_sha

    def scheduled?
      merge_request.cleanup_schedule.present? && merge_request.cleanup_schedule.scheduled_at <= Time.current
    end

    def eligible?
      return met_time_threshold?(merge_request.metrics&.latest_closed_at) if merge_request.closed?

      merge_request.merged? && met_time_threshold?(merge_request.metrics&.merged_at)
    end

    def met_time_threshold?(attr)
      attr.nil? || attr.to_i <= TIME_THRESHOLD.ago.to_i
    end

    def kept_around?
      service = Gitlab::Git::KeepAround.new(repository)

      [ref_head_sha, merge_ref_sha].compact.all? do |sha|
        service.kept_around?(sha)
      end
    end

    def keep_around
      repository.keep_around(ref_head_sha, merge_ref_sha)
    end

    def cache_merge_ref_sha
      return true if merge_ref_sha.nil?

      # Caching the merge ref sha is needed before we delete the merge ref so
      # we can still show the merge ref diff (via `MergeRequest#merge_ref_head`)
      merge_request.update_column(:merge_ref_sha, merge_ref_sha)
    end

    def delete_refs
      merge_request.schedule_cleanup_refs
    end

    def update_schedule
      merge_request.cleanup_schedule.update(completed_at: Time.current)
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe MergeRequests::CleanupRefsService, feature_category: :code_review_workflow do
  describe '.schedule' do
    let(:merge_request) { create(:merge_request) }

    it 'creates a merge request cleanup schedule' do
      freeze_time do
        described_class.schedule(merge_request)

        expect(merge_request.reload.cleanup_schedule.scheduled_at)
          .to eq(described_class::TIME_THRESHOLD.from_now)
      end
    end
  end

  describe '#execute' do
    before do
      stub_feature_flags(merge_request_delete_gitaly_refs_in_batches: false)
      stub_feature_flags(merge_request_cleanup_ref_worker_async: false)

      # Need to re-enable this as it's being stubbed in spec_helper for
      # performance reasons but is needed to run for this test.
      allow(Gitlab::Git::KeepAround).to receive(:execute).and_call_original

      merge_request.create_cleanup_schedule(scheduled_at: described_class::TIME_THRESHOLD.ago)
    end

    subject(:result) { described_class.new(merge_request).execute }

    shared_examples_for 'service that cleans up merge request refs' do
      it 'creates keep around ref and deletes merge request refs' do
        old_ref_head = ref_head

        aggregate_failures do
          expect(result[:status]).to eq(:success)
          expect(kept_around?(old_ref_head)).to be_truthy
          expect(ref_head).to be_nil
          expect(merge_request.cleanup_schedule.completed_at).to be_present
        end
      end

      context 'when merge request has no head ref' do
        before do
          # Simulate a merge request with no head ref
          merge_request.project.repository.delete_refs(merge_request.ref_path)
        end

        it 'does not fail' do
          expect(result[:status]).to eq(:success)
          expect(merge_request.cleanup_schedule.completed_at).to be_present
        end
      end

      context 'when merge request has merge ref' do
        before do
          MergeRequests::MergeToRefService
            .new(project: merge_request.project, current_user: merge_request.author)
            .execute(merge_request)
        end

        it 'caches merge ref sha and deletes merge ref' do
          old_merge_ref_head = merge_request.merge_ref_head

          aggregate_failures do
            expect(result[:status]).to eq(:success)
            expect(kept_around?(old_merge_ref_head)).to be_truthy
            expect(merge_request.reload.merge_ref_sha).to eq(old_merge_ref_head.id)
            expect(ref_exists?(merge_request.merge_ref_path)).to be_falsy
          end
        end

        context 'when merge ref sha cannot be cached' do
          before do
            allow(merge_request)
              .to receive(:update_column)
              .with(:merge_ref_sha, merge_request.merge_ref_head.id)
              .and_return(false)
          end

          it_behaves_like 'service that does not clean up merge request refs'
        end
      end

      context 'when keep around ref cannot be created' do
        before do
          allow_next_instance_of(Gitlab::Git::KeepAround) do |keep_around|
            expect(keep_around).to receive(:kept_around?).and_return(false)
          end
        end

        it_behaves_like 'service that does not clean up merge request refs'
      end

      context 'when a git error is raised' do
        context 'Gitlab::Git::Repository::GitError' do
          before do
            allow(merge_request.project.repository).to receive(:delete_refs).and_raise(Gitlab::Git::Repository::GitError)
          end

          it_behaves_like 'service that does not clean up merge request refs'
        end

        context 'Gitlab::Git::CommandError' do
          before do
            allow_next_instance_of(Gitlab::Git::KeepAround) do |keep_around|
              expect(keep_around).to receive(:kept_around?).and_raise(Gitlab::Git::CommandError)
            end
          end

          it_behaves_like 'service that does not clean up merge request refs'
        end
      end

      context 'when cleanup schedule fails to update' do
        before do
          allow(merge_request.cleanup_schedule).to receive(:update).and_return(false)
        end

        it 'creates keep around ref and deletes merge request refs' do
          old_ref_head = ref_head

          aggregate_failures do
            expect(result[:status]).to eq(:error)
            expect(kept_around?(old_ref_head)).to be_truthy
            expect(ref_head).to be_nil
            expect(merge_request.cleanup_schedule.completed_at).not_to be_present
          end
        end
      end

      context 'when merge request is not scheduled to be cleaned up yet' do
        before do
          merge_request.cleanup_schedule.update!(scheduled_at: 1.day.from_now)
        end

        it_behaves_like 'service that does not clean up merge request refs'
      end

      context 'when repository no longer exists' do
        before do
          Repositories::DestroyService.new(merge_request.project.repository).execute
        end

        it 'does not fail and still mark schedule as complete' do
          aggregate_failures do
            expect(result[:status]).to eq(:success)
            expect(merge_request.cleanup_schedule.completed_at).to be_present
          end
        end
      end
    end

    shared_examples_for 'service that does not clean up merge request refs' do
      it 'does not delete merge request refs' do
        aggregate_failures do
          expect(result[:status]).to eq(:error)
          expect(ref_head).to be_present
          expect(merge_request.cleanup_schedule.completed_at).not_to be_present
        end
      end
    end

    context 'when merge request is closed' do
      let(:merge_request) { create(:merge_request, :closed) }

      context "when closed #{described_class::TIME_THRESHOLD.inspect} ago" do
        before do
          merge_request.metrics.update!(latest_closed_at: described_class::TIME_THRESHOLD.ago)
        end

        it_behaves_like 'service that cleans up merge request refs'
      end

      context "when closed later than #{described_class::TIME_THRESHOLD.inspect} ago" do
        before do
          merge_request.metrics.update!(latest_closed_at: (described_class::TIME_THRESHOLD - 1.day).ago)
        end

        it_behaves_like 'service that does not clean up merge request refs'
      end
    end

    context 'when merge request is merged' do
      let(:merge_request) { create(:merge_request, :merged) }

      context "when merged #{described_class::TIME_THRESHOLD.inspect} ago" do
        before do
          merge_request.metrics.update!(merged_at: described_class::TIME_THRESHOLD.ago)
        end

        it_behaves_like 'service that cleans up merge request refs'
      end

      context "when merged later than #{described_class::TIME_THRESHOLD.inspect} ago" do
        before do
          merge_request.metrics.update!(merged_at: (described_class::TIME_THRESHOLD - 1.day).ago)
        end

        it_behaves_like 'service that does not clean up merge request refs'
      end
    end

    context 'when merge request is not closed nor merged' do
      let(:merge_request) { create(:merge_request, :opened) }

      it_behaves_like 'service that does not clean up merge request refs'
    end
  end

  def kept_around?(commit)
    Gitlab::Git::KeepAround.new(merge_request.project.repository).kept_around?(commit.id)
  end

  def ref_head
    merge_request.project.repository.commit(merge_request.ref_path)
  end

  def ref_exists?(ref)
    merge_request.project.repository.ref_exists?(ref)
  end
end


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

module MergeRequests
  # Performs the merge between source SHA and the target branch or the specified first parent ref. Instead
  # of writing the result to the MR target branch, it targets the `target_ref`.
  #
  # Ideally this should leave the `target_ref` state with the same state the
  # target branch would have if we used the regular `MergeService`, but without
  # every side-effect that comes with it (MR updates, mails, source branch
  # deletion, etc). This service should be kept idempotent (i.e. can
  # be executed regardless of the `target_ref` current state).
  #
  class MergeToRefService < MergeRequests::MergeBaseService
    extend ::Gitlab::Utils::Override

    def execute(merge_request)
      @merge_request = merge_request

      error_check!

      commit_id = extracted_merge_to_ref
      raise_error('Conflicts detected during merge') unless commit_id

      commit = project.commit(commit_id)
      target_id, source_id = commit.parent_ids

      success(commit_id: commit.id, target_id: target_id, source_id: source_id)
    rescue MergeError, ArgumentError => error
      error(error.message)
    end

    private

    def source
      merge_request.diff_head_sha
    end

    override :error_check!
    def error_check!
      raise_error('No source for merge') unless source
    end

    ##
    # The parameter `target_ref` is where the merge result will be written.
    # Default is the merge ref i.e. `refs/merge-requests/:iid/merge`.
    def target_ref
      params[:target_ref] || merge_request.merge_ref_path
    end

    ##
    # The parameter `first_parent_ref` is the main line of the merge commit.
    # Default is the target branch ref of the merge request.
    def first_parent_ref
      params[:first_parent_ref] || merge_request.target_branch_ref
    end

    def commit_message
      params[:commit_message] ||
        merge_request.default_merge_commit_message(user: current_user)
    end

    def extracted_merge_to_ref
      repository.merge_to_ref(current_user,
        source_sha: source,
        branch: merge_request.target_branch,
        target_ref: target_ref,
        message: commit_message,
        first_parent_ref: first_parent_ref)
    rescue Gitlab::Git::PreReceiveError, Gitlab::Git::CommandError => error
      raise MergeError, error.message
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe MergeRequests::MergeToRefService, feature_category: :code_review_workflow do
  shared_examples_for 'MergeService for target ref' do
    it 'target_ref has the same state of target branch' do
      repo = merge_request.target_project.repository

      process_merge_to_ref
      merge_service.execute(merge_request)

      ref_commits = repo.commits(merge_request.merge_ref_path, limit: 3)
      target_branch_commits = repo.commits(merge_request.target_branch, limit: 3)

      ref_commits.zip(target_branch_commits).each do |ref_commit, target_branch_commit|
        expect(ref_commit.parents).to eq(target_branch_commit.parents)
      end
    end
  end

  shared_examples_for 'successfully merges to ref with merge method' do
    it 'writes commit to merge ref' do
      repository = project.repository

      expect(repository.ref_exists?(target_ref)).to be(false)

      result = service.execute(merge_request)

      ref_head = repository.commit(target_ref)

      expect(result[:status]).to eq(:success)
      expect(result[:commit_id]).to be_present
      expect(result[:source_id]).to eq(merge_request.source_branch_sha)
      expect(result[:target_id]).to eq(repository.commit(first_parent_ref).sha)
      expect(repository.ref_exists?(target_ref)).to be(true)
      expect(ref_head.id).to eq(result[:commit_id])
    end
  end

  shared_examples_for 'successfully evaluates pre-condition checks' do
    it 'returns an error when the failing to process the merge' do
      allow(project.repository).to receive(:merge_to_ref).and_return(nil)

      result = service.execute(merge_request)

      expect(result[:status]).to eq(:error)
      expect(result[:message]).to eq('Conflicts detected during merge')
    end

    it 'does not send any mail' do
      expect { process_merge_to_ref }.not_to change { ActionMailer::Base.deliveries.count }
    end

    it 'does not change the MR state' do
      expect { process_merge_to_ref }.not_to change { merge_request.state }
    end

    it 'does not create notes' do
      expect { process_merge_to_ref }.not_to change { merge_request.notes.count }
    end

    it 'does not delete the source branch' do
      expect(::Branches::DeleteService).not_to receive(:new)

      process_merge_to_ref
    end
  end

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

  let(:merge_request) { create(:merge_request, :simple) }
  let(:project) { merge_request.project }

  describe '#execute' do
    let(:service) do
      described_class.new(project: project, current_user: user, params: params)
    end

    let(:params) { { commit_message: 'Awesome message', should_remove_source_branch: true, sha: merge_request.diff_head_sha } }

    def process_merge_to_ref
      perform_enqueued_jobs do
        service.execute(merge_request)
      end
    end

    it_behaves_like 'successfully merges to ref with merge method' do
      let(:first_parent_ref) { 'refs/heads/master' }
      let(:target_ref) { merge_request.merge_ref_path }
    end

    it_behaves_like 'successfully evaluates pre-condition checks'

    it 'returns an error when Gitlab::Git::CommandError is raised during merge' do
      allow(project.repository).to receive(:merge_to_ref) do
        raise Gitlab::Git::CommandError, 'Failed to create merge commit'
      end

      result = service.execute(merge_request)

      expect(result[:status]).to eq(:error)
      expect(result[:message]).to eq('Failed to create merge commit')
    end

    context 'commit history comparison with regular MergeService' do
      before do
        # The merge service needs an authorized user while merge-to-ref
        # doesn't.
        project.add_maintainer(user)
      end

      let(:merge_ref_service) do
        described_class.new(project: project, current_user: user)
      end

      let(:merge_service) do
        MergeRequests::MergeService.new(project: project, current_user: user, params: { sha: merge_request.diff_head_sha })
      end

      context 'when merge commit' do
        it_behaves_like 'MergeService for target ref'
      end

      context 'when merge commit with squash' do
        before do
          merge_request.update!(squash: true)
        end

        it_behaves_like 'successfully merges to ref with merge method' do
          let(:first_parent_ref) { 'refs/heads/master' }
          let(:target_ref) { merge_request.merge_ref_path }
        end

        it 'does not squash before merging' do
          expect(MergeRequests::SquashService).not_to receive(:new)

          process_merge_to_ref
        end
      end
    end

    context 'merge pre-condition checks' do
      before do
        merge_request.project.update!(merge_method: merge_method)
      end

      context 'when semi-linear merge method' do
        let(:merge_method) { :rebase_merge }

        it_behaves_like 'successfully merges to ref with merge method' do
          let(:first_parent_ref) { 'refs/heads/master' }
          let(:target_ref) { merge_request.merge_ref_path }
        end

        it_behaves_like 'successfully evaluates pre-condition checks'
      end

      context 'when fast-forward merge method' do
        let(:merge_method) { :ff }

        it_behaves_like 'successfully merges to ref with merge method' do
          let(:first_parent_ref) { 'refs/heads/master' }
          let(:target_ref) { merge_request.merge_ref_path }
        end

        it_behaves_like 'successfully evaluates pre-condition checks'
      end

      context 'when MR is not mergeable to ref' do
        let(:merge_method) { :merge }

        it 'returns error' do
          allow(project).to receive_message_chain(:repository, :merge_to_ref) { nil }

          error_message = 'Conflicts detected during merge'

          result = service.execute(merge_request)

          expect(result[:status]).to eq(:error)
          expect(result[:message]).to eq(error_message)
        end
      end
    end

    context 'does not close related todos' do
      let(:merge_request) { create(:merge_request, assignees: [user], author: user) }
      let(:project) { merge_request.project }
      let!(:todo) do
        create(
          :todo,
          :assigned,
          project: project,
          author: user,
          user: user,
          target: merge_request
        )
      end

      before do
        allow(service).to receive(:execute_hooks)

        perform_enqueued_jobs do
          service.execute(merge_request)
          todo.reload
        end
      end

      it { expect(todo).not_to be_done }
    end

    context 'when source is missing' do
      it 'returns error' do
        allow(merge_request).to receive(:diff_head_sha) { nil }

        error_message = 'No source for merge'

        result = service.execute(merge_request)

        expect(result[:status]).to eq(:error)
        expect(result[:message]).to eq(error_message)
      end
    end

    context 'when target ref is passed as a parameter' do
      let(:params) { { commit_message: 'merge train', target_ref: target_ref, sha: merge_request.diff_head_sha } }

      it_behaves_like 'successfully merges to ref with merge method' do
        let(:first_parent_ref) { 'refs/heads/master' }
        let(:target_ref) { 'refs/merge-requests/1/train' }
      end
    end

    describe 'cascading merge refs' do
      let_it_be(:project) { create(:project, :repository) }

      let(:params) { { commit_message: 'Cascading merge', first_parent_ref: first_parent_ref, target_ref: target_ref, sha: merge_request.diff_head_sha } }

      context 'when first merge happens' do
        let(:merge_request) do
          create(
            :merge_request, source_project: project, source_branch: 'feature',
            target_project: project, target_branch: 'master'
          )
        end

        it_behaves_like 'successfully merges to ref with merge method' do
          let(:first_parent_ref) { 'refs/heads/master' }
          let(:target_ref) { 'refs/merge-requests/1/train' }
        end

        context 'when second merge happens' do
          let(:merge_request) do
            create(
              :merge_request,
              source_project: project, source_branch: 'improve/awesome',
              target_project: project, target_branch: 'master'
            )
          end

          it_behaves_like 'successfully merges to ref with merge method' do
            let(:first_parent_ref) { 'refs/merge-requests/1/train' }
            let(:target_ref) { 'refs/merge-requests/2/train' }
          end
        end
      end
    end
  end
end


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

module MergeRequests
  class CreateApprovalEventService < MergeRequests::BaseService
    def execute(merge_request)
      event_service.approve_mr(merge_request, current_user)
    end
  end
end

MergeRequests::CreateApprovalEventService.prepend_mod

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe MergeRequests::CreateApprovalEventService, feature_category: :code_review_workflow do
  let(:user) { create(:user) }
  let(:merge_request) { create(:merge_request) }
  let(:project) { merge_request.project }

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

  describe '#execute' do
    it 'creates approve MR event' do
      expect_next_instance_of(EventCreateService) do |instance|
        expect(instance).to receive(:approve_mr)
          .with(merge_request, user)
      end

      service.execute(merge_request)
    end
  end
end


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

module MergeRequests
  class ReopenService < MergeRequests::BaseService
    def execute(merge_request)
      return merge_request unless can?(current_user, :reopen_merge_request, merge_request)

      if merge_request.reopen
        users = merge_request.assignees | merge_request.reviewers

        create_event(merge_request)
        create_note(merge_request, 'reopened')
        merge_request_activity_counter.track_reopen_mr_action(user: current_user)
        notification_service.async.reopen_mr(merge_request, current_user)
        execute_hooks(merge_request, 'reopen')
        merge_request.reload_diff(current_user)
        merge_request.mark_as_unchecked
        invalidate_cache_counts(merge_request, users: users)
        merge_request.update_project_counter_caches
        merge_request.cache_merge_request_closes_issues!(current_user)
        merge_request.cleanup_schedule&.destroy
        merge_request.update_column(:merge_ref_sha, nil)
      end

      merge_request
    end

    private

    def create_event(merge_request)
      # Making sure MergeRequest::Metrics updates are in sync with
      # Event creation.
      Event.transaction do
        event_service.reopen_mr(merge_request, current_user)
        merge_request_metrics_service(merge_request).reopen
      end
    end
  end
end

MergeRequests::ReopenService.prepend_mod

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe MergeRequests::ReopenService, feature_category: :code_review_workflow do
  let(:user) { create(:user) }
  let(:user2) { create(:user) }
  let(:guest) { create(:user) }
  let(:merge_request) { create(:merge_request, :closed, assignees: [user2], author: create(:user)) }
  let(:project) { merge_request.project }

  before do
    project.add_maintainer(user)
    project.add_developer(user2)
    project.add_guest(guest)
  end

  describe '#execute' do
    it_behaves_like 'cache counters invalidator'
    it_behaves_like 'merge request reviewers cache counters invalidator'

    context 'valid params' do
      let(:service) { described_class.new(project: project, current_user: user) }

      before do
        allow(service).to receive(:execute_hooks)
        merge_request.create_cleanup_schedule(scheduled_at: Time.current)
        merge_request.update_column(:merge_ref_sha, 'abc123')

        perform_enqueued_jobs do
          service.execute(merge_request)
        end
      end

      it { expect(merge_request).to be_valid }
      it { expect(merge_request).to be_opened }

      it 'executes hooks with reopen action' do
        expect(service).to have_received(:execute_hooks)
                               .with(merge_request, 'reopen')
      end

      it 'does not call GroupMentionWorker' do
        expect(Integrations::GroupMentionWorker).not_to receive(:perform_async)
      end

      it 'sends email to user2 about reopen of merge_request', :sidekiq_inline do
        email = ActionMailer::Base.deliveries.last
        expect(email.to.first).to eq(user2.email)
        expect(email.subject).to include(merge_request.title)
      end

      it 'destroys cleanup schedule record' do
        expect(merge_request.reload.cleanup_schedule).to be_nil
      end

      it 'clears the cached merge_ref_sha' do
        expect(merge_request.reload.merge_ref_sha).to be_nil
      end

      context 'note creation' do
        it 'creates resource state event about merge_request reopen' do
          event = merge_request.resource_state_events.last
          expect(event.state).to eq('reopened')
        end
      end
    end

    it 'caches merge request closing issues' do
      expect(merge_request).to receive(:cache_merge_request_closes_issues!)

      described_class.new(project: project, current_user: user).execute(merge_request)
    end

    it 'updates metrics' do
      metrics = merge_request.metrics
      service = double(MergeRequestMetricsService)
      allow(MergeRequestMetricsService)
        .to receive(:new)
        .with(metrics)
        .and_return(service)

      expect(service).to receive(:reopen)

      described_class.new(project: project, current_user: user).execute(merge_request)
    end

    it 'calls the merge request activity counter' do
      expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
        .to receive(:track_reopen_mr_action)
        .with(user: user)

      described_class.new(project: project, current_user: user).execute(merge_request)
    end

    it 'refreshes the number of open merge requests for a valid MR' do
      service = described_class.new(project: project, current_user: user)

      expect do
        service.execute(merge_request)

        BatchLoader::Executor.clear_current
      end
        .to change { project.open_merge_requests_count }.from(0).to(1)
    end

    context 'current user is not authorized to reopen merge request' do
      before do
        perform_enqueued_jobs do
          @merge_request = described_class.new(project: project, current_user: guest).execute(merge_request)
        end
      end

      it 'does not reopen the merge request' do
        expect(@merge_request).to be_closed
      end
    end
  end
end