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

class ResetProjectCacheService < BaseService
  def execute
    @project.increment!(:jobs_cache_index)
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe ResetProjectCacheService, feature_category: :groups_and_projects do
  let(:project) { create(:project) }
  let(:user) { create(:user) }

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

  context 'when project cache_index is nil' do
    before do
      project.jobs_cache_index = nil
    end

    it 'sets project cache_index to one' do
      expect { subject }.to change { project.reload.jobs_cache_index }.from(nil).to(1)
    end
  end

  context 'when project cache_index is a numeric value' do
    before do
      project.update!(jobs_cache_index: 1)
    end

    it 'increments project cache index' do
      expect { subject }.to change { project.reload.jobs_cache_index }.by(1)
    end
  end
end


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

class BulkUpdateIntegrationService
  include Integrations::BulkOperationHashes

  def initialize(integration, batch)
    @integration = integration
    @batch = batch
  end

  # rubocop: disable CodeReuse/ActiveRecord
  def execute
    Integration.transaction do
      Integration.where(id: batch_ids).update_all(integration_hash(:update))

      if integration.data_fields_present?
        integration.data_fields.class.where(data_fields_foreign_key => batch_ids)
          .update_all(
            data_fields_hash(:update)
          )
      end
    end
  end
  # rubocop: enable CodeReuse/ActiveRecord

  private

  attr_reader :integration, :batch

  # service_id or integration_id
  def data_fields_foreign_key
    integration.data_fields.class.reflections['integration'].foreign_key
  end

  def batch_ids
    @batch_ids ||=
      if batch.is_a?(ActiveRecord::Relation)
        batch.select(:id)
      else
        batch.map(&:id)
      end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe BulkUpdateIntegrationService, feature_category: :integrations do
  include JiraIntegrationHelpers

  before_all do
    stub_jira_integration_test
  end

  let(:excluded_attributes) do
    %w[
      id project_id group_id inherit_from_id instance template
      created_at updated_at encrypted_properties encrypted_properties_iv
    ]
  end

  let(:batch) do
    Integration.inherited_descendants_from_self_or_ancestors_from(subgroup_integration).where(id: group_integration.id..integration.id)
  end

  let_it_be(:group) { create(:group) }
  let_it_be(:subgroup) { create(:group, parent: group) }
  let_it_be(:group_integration) { create(:jira_integration, :group, group: group, url: 'http://group.jira.com') }
  let_it_be(:excluded_integration) { create(:jira_integration, :group, group: create(:group), url: 'http://another.jira.com', push_events: false) }
  let_it_be(:subgroup_integration) do
    create(:jira_integration, :group,
      group: subgroup,
      inherit_from_id: group_integration.id,
      url: 'http://subgroup.jira.com',
      push_events: true
    )
  end

  let_it_be(:integration) do
    create(:jira_integration,
      project: create(:project, group: subgroup),
      inherit_from_id: subgroup_integration.id,
      url: 'http://project.jira.com',
      push_events: false
    )
  end

  context 'with inherited integration' do
    it 'updates the integration', :aggregate_failures do
      described_class.new(subgroup_integration.reload, batch).execute

      expect(integration.reload.inherit_from_id).to eq(group_integration.id)
      expect(integration.reload.attributes.except(*excluded_attributes))
        .to eq(subgroup_integration.reload.attributes.except(*excluded_attributes))

      expect(excluded_integration.reload.inherit_from_id).not_to eq(group_integration.id)
      expect(excluded_integration.reload.attributes.except(*excluded_attributes))
        .not_to eq(subgroup_integration.attributes.except(*excluded_attributes))
    end

    it 'does not change the created_at timestamp' do
      subgroup_integration.update_column(:created_at, Time.utc(2022, 1, 1))

      expect do
        described_class.new(subgroup_integration, batch).execute
      end.not_to change { integration.reload.created_at }
    end

    it 'sets the updated_at timestamp to the current time', time_travel_to: Time.utc(2022, 1, 1) do
      expect do
        described_class.new(subgroup_integration, batch).execute
      end.to change { integration.reload.updated_at }.to(Time.current)
    end

    context 'with integration with data fields' do
      let(:excluded_attributes) do
        %w[id integration_id created_at updated_at encrypted_properties encrypted_properties_iv]
      end

      it 'updates the data fields from the integration', :aggregate_failures do
        described_class.new(subgroup_integration, batch).execute

        expect(integration.reload.data_fields.attributes.except(*excluded_attributes))
          .to eq(subgroup_integration.reload.data_fields.attributes.except(*excluded_attributes))

        expect(integration.data_fields.attributes.except(*excluded_attributes))
          .not_to eq(excluded_integration.data_fields.attributes.except(*excluded_attributes))
      end

      it 'does not change the created_at timestamp' do
        subgroup_integration.data_fields.update_column(:created_at, Time.utc(2022, 1, 2))

        expect do
          described_class.new(subgroup_integration, batch).execute
        end.not_to change { integration.data_fields.reload.created_at }
      end

      it 'sets the updated_at timestamp to the current time', time_travel_to: Time.utc(2022, 1, 1) do
        expect do
          described_class.new(subgroup_integration, batch).execute
        end.to change { integration.data_fields.reload.updated_at }.to(Time.current)
      end
    end
  end

  it 'works with batch as an ActiveRecord::Relation' do
    expect do
      described_class.new(group_integration, Integration.where(id: integration.id)).execute
    end.to change { integration.reload.url }.to(group_integration.url)
  end

  it 'works with batch as an array of ActiveRecord objects' do
    expect do
      described_class.new(group_integration, [integration]).execute
    end.to change { integration.reload.url }.to(group_integration.url)
  end

  context 'with different foreign key of data_fields' do
    let(:integration) { create(:zentao_integration, project: create(:project, group: group)) }
    let(:group_integration) do
      create(:zentao_integration, :group,
        group: group,
        url: 'https://group.zentao.net',
        api_token: 'GROUP_TOKEN',
        zentao_product_xid: '1'
      )
    end

    it 'works with batch as an array of ActiveRecord objects' do
      expect do
        described_class.new(group_integration, [integration]).execute
      end.to change { integration.reload.url }.to(group_integration.url)
    end
  end
end


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

class ServiceResponse
  def self.success(message: nil, payload: {}, http_status: :ok)
    new(
      status: :success,
      message: message,
      payload: payload,
      http_status: http_status
    )
  end

  def self.error(message:, payload: {}, http_status: nil, reason: nil)
    new(
      status: :error,
      message: message,
      payload: payload,
      http_status: http_status,
      reason: reason
    )
  end

  attr_reader :status, :message, :http_status, :payload, :reason

  def initialize(status:, message: nil, payload: {}, http_status: nil, reason: nil)
    self.status = status
    self.message = message
    self.payload = payload
    self.http_status = http_status
    self.reason = reason
  end

  def log_and_raise_exception(as: StandardError, **extra_data)
    error_tracking(as) do |ex|
      Gitlab::ErrorTracking.log_and_raise_exception(ex, extra_data)
    end
  end

  def track_exception(as: StandardError, **extra_data)
    error_tracking(as) do |ex|
      Gitlab::ErrorTracking.track_exception(ex, extra_data)
    end
  end

  def track_and_raise_exception(as: StandardError, **extra_data)
    error_tracking(as) do |ex|
      Gitlab::ErrorTracking.track_and_raise_exception(ex, extra_data)
    end
  end

  def [](key)
    to_h[key]
  end

  def to_h
    (payload || {}).merge(
      status: status,
      message: message,
      http_status: http_status,
      reason: reason)
  end

  def deconstruct_keys(keys)
    to_h.slice(*keys)
  end

  def success?
    status == :success
  end

  def error?
    status == :error
  end

  def errors
    return [] unless error?

    Array.wrap(message)
  end

  private

  attr_writer :status, :message, :http_status, :payload, :reason

  def error_tracking(error_klass)
    if error?
      ex = error_klass.new(message)
      yield ex
    end

    self
  end
end

```

Response:
# frozen_string_literal: true

require 'fast_spec_helper'

require 're2'

require_relative '../../app/services/service_response'
require_relative '../../lib/gitlab/error_tracking'

RSpec.describe ServiceResponse, feature_category: :shared do
  describe '.success' do
    it 'creates a successful response without a message' do
      expect(described_class.success).to be_success
    end

    it 'creates a successful response with a message' do
      response = described_class.success(message: 'Good orange')

      expect(response).to be_success
      expect(response.message).to eq('Good orange')
    end

    it 'creates a successful response with payload' do
      response = described_class.success(payload: { good: 'orange' })

      expect(response).to be_success
      expect(response.payload).to eq(good: 'orange')
    end

    it 'creates a successful response with default HTTP status' do
      response = described_class.success

      expect(response).to be_success
      expect(response.http_status).to eq(:ok)
    end

    it 'creates a successful response with custom HTTP status' do
      response = described_class.success(http_status: 204)

      expect(response).to be_success
      expect(response.http_status).to eq(204)
    end
  end

  describe '.error' do
    it 'creates an error response without HTTP status' do
      response = described_class.error(message: 'Bad apple')

      expect(response).to be_error
      expect(response.message).to eq('Bad apple')
    end

    it 'creates an error response with HTTP status' do
      response = described_class.error(message: 'Bad apple', http_status: 400)

      expect(response).to be_error
      expect(response.message).to eq('Bad apple')
      expect(response.http_status).to eq(400)
    end

    it 'creates an error response with payload' do
      response = described_class.error(message: 'Bad apple', payload: { bad: 'apple' })

      expect(response).to be_error
      expect(response.message).to eq('Bad apple')
      expect(response.payload).to eq(bad: 'apple')
    end

    it 'creates an error response with a reason' do
      response = described_class.error(message: 'Bad apple', reason: :permission_denied)

      expect(response).to be_error
      expect(response.message).to eq('Bad apple')
      expect(response.reason).to eq(:permission_denied)
    end
  end

  describe '#success?' do
    it 'returns true for a successful response' do
      expect(described_class.success.success?).to eq(true)
    end

    it 'returns false for a failed response' do
      expect(described_class.error(message: 'Bad apple').success?).to eq(false)
    end
  end

  describe '#error?' do
    it 'returns false for a successful response' do
      expect(described_class.success.error?).to eq(false)
    end

    it 'returns true for a failed response' do
      expect(described_class.error(message: 'Bad apple').error?).to eq(true)
    end
  end

  describe '#errors' do
    it 'returns an empty array for a successful response' do
      expect(described_class.success.errors).to be_empty
    end

    it 'returns an array with a correct message for an error response' do
      expect(described_class.error(message: 'error message').errors).to eq(['error message'])
    end
  end

  describe '#track_and_raise_exception' do
    context 'when successful' do
      let(:response) { described_class.success }

      it 'returns self' do
        expect(response.track_and_raise_exception).to be response
      end
    end

    context 'when an error' do
      let(:response) { described_class.error(message: 'bang') }

      it 'tracks and raises' do
        expect(::Gitlab::ErrorTracking).to receive(:track_and_raise_exception)
          .with(StandardError.new('bang'), {})

        response.track_and_raise_exception
      end

      it 'allows specification of error class' do
        error = Class.new(StandardError)
        expect(::Gitlab::ErrorTracking).to receive(:track_and_raise_exception)
          .with(error.new('bang'), {})

        response.track_and_raise_exception(as: error)
      end

      it 'allows extra data for tracking' do
        expect(::Gitlab::ErrorTracking).to receive(:track_and_raise_exception)
          .with(StandardError.new('bang'), { foo: 1, bar: 2 })

        response.track_and_raise_exception(foo: 1, bar: 2)
      end
    end
  end

  describe '#track_exception' do
    context 'when successful' do
      let(:response) { described_class.success }

      it 'returns self' do
        expect(response.track_exception).to be response
      end
    end

    context 'when an error' do
      let(:response) { described_class.error(message: 'bang') }

      it 'tracks' do
        expect(::Gitlab::ErrorTracking).to receive(:track_exception)
          .with(StandardError.new('bang'), {})

        expect(response.track_exception).to be response
      end

      it 'allows specification of error class' do
        error = Class.new(StandardError)
        expect(::Gitlab::ErrorTracking).to receive(:track_exception)
          .with(error.new('bang'), {})

        expect(response.track_exception(as: error)).to be response
      end

      it 'allows extra data for tracking' do
        expect(::Gitlab::ErrorTracking).to receive(:track_exception)
          .with(StandardError.new('bang'), { foo: 1, bar: 2 })

        expect(response.track_exception(foo: 1, bar: 2)).to be response
      end
    end
  end

  describe '#log_and_raise_exception' do
    context 'when successful' do
      let(:response) { described_class.success }

      it 'returns self' do
        expect(response.log_and_raise_exception).to be response
      end
    end

    context 'when an error' do
      let(:response) { described_class.error(message: 'bang') }

      it 'logs' do
        expect(::Gitlab::ErrorTracking).to receive(:log_and_raise_exception)
          .with(StandardError.new('bang'), {})

        response.log_and_raise_exception
      end

      it 'allows specification of error class' do
        error = Class.new(StandardError)
        expect(::Gitlab::ErrorTracking).to receive(:log_and_raise_exception)
          .with(error.new('bang'), {})

        response.log_and_raise_exception(as: error)
      end

      it 'allows extra data for tracking' do
        expect(::Gitlab::ErrorTracking).to receive(:log_and_raise_exception)
          .with(StandardError.new('bang'), { foo: 1, bar: 2 })

        response.log_and_raise_exception(foo: 1, bar: 2)
      end
    end
  end

  describe '#deconstruct_keys' do
    it 'supports pattern matching' do
      status =
        case described_class.error(message: 'Bad apple')
        in { status: Symbol => status }
          status
        else
          raise
        end
      expect(status).to eq(:error)
    end
  end
end


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

class BulkCreateIntegrationService
  include Integrations::BulkOperationHashes

  def initialize(integration, batch, association)
    @integration = integration
    @batch = batch
    @association = association
  end

  def execute
    integration_list = Integrations::IntegrationList.new(batch, integration_hash(:create), association).to_array

    Integration.transaction do
      results = bulk_insert(*integration_list)

      if integration.data_fields_present?
        data_list = DataList.new(results, data_fields_hash(:create), integration.data_fields.class).to_array

        bulk_insert(*data_list)
      end
    end
  end

  private

  attr_reader :integration, :batch, :association

  def bulk_insert(klass, columns, values_array)
    items_to_insert = values_array.map { |array| Hash[columns.zip(array)] }

    klass.insert_all(items_to_insert, returning: [:id])
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe BulkCreateIntegrationService, feature_category: :integrations do
  include JiraIntegrationHelpers

  before_all do
    stub_jira_integration_test
  end

  let_it_be(:excluded_group) { create(:group) }
  let_it_be(:excluded_project) { create(:project, group: excluded_group) }

  let(:instance_integration) { create(:jira_integration, :instance) }
  let(:excluded_attributes) do
    %w[
      id project_id group_id inherit_from_id instance template
      created_at updated_at
      encrypted_properties encrypted_properties_iv
    ]
  end

  shared_examples 'creates integration successfully' do
    def attributes(record)
      record.reload.attributes.except(*excluded_attributes)
    end

    it 'updates the inherited integrations' do
      described_class.new(integration, batch, association).execute

      expect(attributes(created_integration)).to eq attributes(integration)
    end

    context 'integration with data fields' do
      let(:excluded_attributes) { %w[id service_id integration_id created_at updated_at] }

      it 'updates the data fields from inherited integrations' do
        described_class.new(integration, batch, association).execute

        expect(attributes(created_integration.data_fields))
          .to eq attributes(integration.data_fields)
      end

      it 'sets created_at and updated_at timestamps', :freeze_time do
        described_class.new(integration, batch, association).execute

        expect(created_integration.data_fields.reload).to have_attributes(
          created_at: eq(Time.current),
          updated_at: eq(Time.current)
        )
      end
    end

    it 'updates inherit_from_id attributes' do
      described_class.new(integration, batch, association).execute

      expect(created_integration.reload.inherit_from_id).to eq(inherit_from_id)
    end

    it 'sets created_at and updated_at timestamps', :freeze_time do
      described_class.new(integration, batch, association).execute

      expect(created_integration.reload).to have_attributes(
        created_at: eq(Time.current),
        updated_at: eq(Time.current)
      )
    end
  end

  context 'passing an instance-level integration' do
    let(:integration) { instance_integration }
    let(:inherit_from_id) { integration.id }

    context 'with a project association' do
      let!(:project) { create(:project) }
      let(:created_integration) { project.jira_integration }
      let(:batch) { Project.where(id: project.id) }
      let(:association) { 'project' }

      it_behaves_like 'creates integration successfully'
    end

    context 'with a group association' do
      let!(:group) { create(:group) }
      let(:created_integration) { Integration.find_by(group: group) }
      let(:batch) { Group.where(id: group.id) }
      let(:association) { 'group' }

      it_behaves_like 'creates integration successfully'
    end
  end

  context 'passing a group integration' do
    let_it_be(:group) { create(:group) }

    context 'with a project association' do
      let!(:project) { create(:project, group: group) }
      let(:integration) { create(:jira_integration, :group, group: group) }
      let(:created_integration) { project.jira_integration }
      let(:batch) { Project.where(id: Project.minimum(:id)..Project.maximum(:id)).without_integration(integration).in_namespace(integration.group.self_and_descendants) }
      let(:association) { 'project' }
      let(:inherit_from_id) { integration.id }

      it_behaves_like 'creates integration successfully'

      context 'with different foreign key of data_fields' do
        let(:integration) { create(:zentao_integration, :group, group: group) }
        let(:created_integration) { project.zentao_integration }

        it_behaves_like 'creates integration successfully'
      end
    end

    context 'with a group association' do
      let!(:subgroup) { create(:group, parent: group) }
      let(:integration) { create(:jira_integration, :group, group: group, inherit_from_id: instance_integration.id) }
      let(:created_integration) { Integration.find_by(group: subgroup) }
      let(:batch) { Group.where(id: subgroup.id) }
      let(:association) { 'group' }
      let(:inherit_from_id) { instance_integration.id }

      it_behaves_like 'creates integration successfully'

      context 'with different foreign key of data_fields' do
        let(:integration) { create(:zentao_integration, :group, group: group, inherit_from_id: instance_integration.id) }

        it_behaves_like 'creates integration successfully'
      end
    end
  end
end


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

# PostReceiveService class
#
# Used for scheduling related jobs after a push action has been performed
class PostReceiveService
  attr_reader :user, :repository, :project, :params

  def initialize(user, repository, project, params)
    @user = user
    @repository = repository
    @project = project
    @params = params
  end

  def execute
    response = Gitlab::InternalPostReceive::Response.new

    push_options = Gitlab::PushOptions.new(params[:push_options])
    mr_options = push_options.get(:merge_request)

    response.reference_counter_decreased = Gitlab::ReferenceCounter.new(params[:gl_repository]).decrease

    # The PostReceive worker will normally invalidate the cache. However, it
    # runs asynchronously. If push options require us to create a new merge
    # request synchronously, we can't rely on that, so invalidate the cache here
    repository&.expire_branches_cache if mr_options&.fetch(:create, false)

    PostReceive.perform_async(params[:gl_repository], params[:identifier],
                              params[:changes], push_options.as_json)

    if mr_options.present?
      message = process_mr_push_options(mr_options, params[:changes])
      response.add_alert_message(message)
    end

    response.add_alert_message(broadcast_message)
    response.add_merge_request_urls(merge_request_urls)

    # Neither User nor Repository are guaranteed to be returned; an orphaned write deploy
    # key could be used
    if user && repository
      redirect_message = Gitlab::Checks::ContainerMoved.fetch_message(user, repository)
      project_created_message = Gitlab::Checks::ProjectCreated.fetch_message(user, repository)

      response.add_basic_message(redirect_message)
      response.add_basic_message(project_created_message)

      record_onboarding_progress
    end

    response
  end

  def process_mr_push_options(push_options, changes)
    Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/-/issues/28494')
    return unless repository

    unless repository.repo_type.project?
      return push_options_warning('Push options are only supported for projects')
    end

    service = ::MergeRequests::PushOptionsHandlerService.new(
      project: project, current_user: user, changes: changes, push_options: push_options
    ).execute

    if service.errors.present?
      push_options_warning(service.errors.join("\n\n"))
    end
  end

  def push_options_warning(warning)
    options = Array.wrap(params[:push_options]).map { |p| "'#{p}'" }.join(' ')
    "WARNINGS:\nError encountered with push options #{options}: #{warning}"
  end

  def merge_request_urls
    return [] unless repository&.repo_type&.project?

    ::MergeRequests::GetUrlsService.new(project: project).execute(params[:changes])
  end

  private

  def broadcast_message
    banner = nil

    if project
      scoped_messages =
        System::BroadcastMessage.current_banner_messages(current_path: project.full_path).select do |message|
          message.target_path.present? && message.matches_current_path(project.full_path) && message.show_in_cli?
        end

      banner = scoped_messages.last
    end

    banner ||= System::BroadcastMessage.current_show_in_cli_banner_messages.last

    banner&.message
  end

  def record_onboarding_progress
    return unless project

    Onboarding::ProgressService.new(project.namespace).execute(action: :git_write)
  end
end

PostReceiveService.prepend_mod_with('PostReceiveService')

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe PostReceiveService, feature_category: :team_planning do
  include GitlabShellHelpers
  include Gitlab::Routing

  let_it_be(:user) { create(:user) }
  let_it_be(:project) { create(:project, :repository, :wiki_repo, namespace: user.namespace) }
  let_it_be(:project_snippet) { create(:project_snippet, :repository, project: project, author: user) }
  let_it_be(:personal_snippet) { create(:personal_snippet, :repository, author: user) }

  let(:identifier) { 'key-123' }
  let(:gl_repository) { "project-#{project.id}" }
  let(:branch_name) { 'feature' }
  let(:reference_counter) { double('ReferenceCounter') }
  let(:push_options) { ['ci.skip', 'another push option'] }
  let(:repository) { project.repository }

  let(:changes) do
    "#{Gitlab::Git::BLANK_SHA} 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/#{branch_name}"
  end

  let(:params) do
    {
      gl_repository: gl_repository,
      identifier: identifier,
      changes: changes,
      push_options: push_options
    }
  end

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

  subject { response.messages.as_json }

  context 'when project is nil' do
    let(:gl_repository) { "snippet-#{personal_snippet.id}" }
    let(:project) { nil }
    let(:repository) { personal_snippet.repository }

    it 'does not return error' do
      expect(subject).to be_empty
    end

    it_behaves_like 'does not record an onboarding progress action'
  end

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

    it 'does not return error' do
      expect(subject).to be_empty
    end
  end

  context 'when both repository and project are nil' do
    let(:gl_repository) { "snippet-#{personal_snippet.id}" }
    let(:project) { nil }
    let(:repository) { nil }

    it 'does not return error' do
      expect(subject).to be_empty
    end
  end

  shared_examples 'post_receive_service actions' do
    it 'enqueues a PostReceive worker job' do
      expect(PostReceive).to receive(:perform_async)
        .with(gl_repository, identifier, changes, { ci: { skip: true } })

      subject
    end

    it 'decreases the reference counter and returns the result' do
      expect(Gitlab::ReferenceCounter).to receive(:new).with(gl_repository)
        .and_return(reference_counter)
      expect(reference_counter).to receive(:decrease).and_return(true)

      expect(response.reference_counter_decreased).to be(true)
    end

    it_behaves_like 'records an onboarding progress action', :git_write do
      let(:namespace) { project.namespace }
    end
  end

  context 'with Project' do
    it_behaves_like 'post_receive_service actions'

    it 'returns link to create new merge request' do
      message = <<~MESSAGE.strip
        To create a merge request for #{branch_name}, visit:
          http://#{Gitlab.config.gitlab.host}/#{project.full_path}/-/merge_requests/new?merge_request%5Bsource_branch%5D=#{branch_name}
      MESSAGE

      expect(subject).to include(build_basic_message(message))
    end

    it 'returns the link to an existing merge request when it exists' do
      merge_request = create(:merge_request, source_project: project, source_branch: branch_name, target_branch: 'master')
      message = <<~MESSAGE.strip
        View merge request for feature:
          #{project_merge_request_url(project, merge_request)}
      MESSAGE

      expect(subject).to include(build_basic_message(message))
    end

    context 'when printing_merge_request_link_enabled is false' do
      let(:project) { create(:project, printing_merge_request_link_enabled: false) }

      it 'returns no merge request messages' do
        expect(subject).to be_blank
      end
    end

    it 'does not invoke MergeRequests::PushOptionsHandlerService' do
      expect(MergeRequests::PushOptionsHandlerService).not_to receive(:new)

      subject
    end

    context 'when there are merge_request push options' do
      let(:params) { super().merge(push_options: ['merge_request.create']) }

      before do
        project.add_developer(user)
      end

      it 'invalidates the branch name cache' do
        expect(service.repository).to receive(:expire_branches_cache).and_call_original

        subject
      end

      it 'invokes MergeRequests::PushOptionsHandlerService' do
        expect(MergeRequests::PushOptionsHandlerService).to receive(:new).and_call_original

        subject
      end

      it 'creates a new merge request' do
        expect { Sidekiq::Testing.fake! { subject } }.to change(MergeRequest, :count).by(1)
      end

      it 'links to the newly created merge request' do
        message = <<~MESSAGE.strip
          View merge request for #{branch_name}:
            http://#{Gitlab.config.gitlab.host}/#{project.full_path}/-/merge_requests/1
        MESSAGE

        expect(subject).to include(build_basic_message(message))
      end

      it 'adds errors on the service instance to warnings' do
        expect_any_instance_of(
          MergeRequests::PushOptionsHandlerService
        ).to receive(:errors).at_least(:once).and_return(['my error'])

        message = "WARNINGS:\nError encountered with push options 'merge_request.create': my error"

        expect(subject).to include(build_alert_message(message))
      end

      it 'adds ActiveRecord errors on invalid MergeRequest records to warnings' do
        invalid_merge_request = MergeRequest.new
        invalid_merge_request.errors.add(:base, 'my error')
        message = "WARNINGS:\nError encountered with push options 'merge_request.create': my error"

        expect_any_instance_of(
          MergeRequests::CreateService
        ).to receive(:execute).and_return(invalid_merge_request)

        expect(subject).to include(build_alert_message(message))
      end
    end
  end

  context 'with PersonalSnippet' do
    let(:gl_repository) { "snippet-#{personal_snippet.id}" }
    let(:repository) { personal_snippet.repository }

    it_behaves_like 'post_receive_service actions'

    it 'does not return link to create new merge request' do
      expect(subject).to be_empty
    end

    it 'does not return the link to an existing merge request when it exists' do
      create(:merge_request, source_project: project, source_branch: branch_name, target_branch: 'master')

      expect(subject).to be_empty
    end
  end

  context 'with ProjectSnippet' do
    let(:gl_repository) { "snippet-#{project_snippet.id}" }
    let(:repository) { project_snippet.repository }

    it_behaves_like 'post_receive_service actions'

    it 'does not return link to create new merge request' do
      expect(subject).to be_empty
    end

    it 'does not return the link to an existing merge request when it exists' do
      create(:merge_request, source_project: project, source_branch: branch_name, target_branch: 'master')

      expect(subject).to be_empty
    end
  end

  context 'broadcast message banner exists' do
    it 'outputs a broadcast message when show_in_cli is true' do
      broadcast_message = create(:broadcast_message, show_in_cli: true)

      expect(subject).to include(build_alert_message(broadcast_message.message))
    end

    it 'does not output a broadcast message when show_in_cli is false' do
      create(:broadcast_message, show_in_cli: false)

      expect(has_alert_messages?(subject)).to be_falsey
    end
  end

  context 'broadcast message notification exists' do
    it 'does not output a broadcast message' do
      create(:broadcast_message, :notification)

      expect(has_alert_messages?(subject)).to be_falsey
    end
  end

  context 'broadcast message does not exist' do
    it 'does not output a broadcast message' do
      expect(has_alert_messages?(subject)).to be_falsey
    end
  end

  context 'nil broadcast message' do
    it 'does not output a broadcast message' do
      allow(System::BroadcastMessage).to receive(:current).and_return(nil)

      expect(has_alert_messages?(subject)).to be_falsey
    end
  end

  context "broadcast message has a target_path" do
    let!(:older_scoped_message) do
      create(:broadcast_message, message: "Old top secret", target_path: "/company/sekrit-project")
    end

    let!(:latest_scoped_message) do
      create(:broadcast_message, message: "Top secret", target_path: "/company/sekrit-project")
    end

    let!(:unscoped_message) do
      create(:broadcast_message, message: "Hi")
    end

    context "no project path matches" do
      it "does not output the scoped broadcast messages" do
        expect(subject).not_to include(build_alert_message(older_scoped_message.message))
        expect(subject).not_to include(build_alert_message(latest_scoped_message.message))
      end

      it "does output another message that doesn't have a target_path" do
        expect(subject).to include(build_alert_message(unscoped_message.message))
      end
    end

    context "project path matches" do
      before do
        allow(project).to receive(:full_path).and_return("company/sekrit-project")
      end

      it "does output the latest scoped broadcast message" do
        expect(subject).to include(build_alert_message(latest_scoped_message.message))
      end

      it "does not output the older scoped broadcast message" do
        expect(subject).not_to include(build_alert_message(older_scoped_message.message))
      end

      it "does not output another message that doesn't have a target_path" do
        expect(subject).not_to include(build_alert_message(unscoped_message.message))
      end
    end
  end

  context 'with a redirected data' do
    it 'returns redirected message on the response' do
      project_moved = Gitlab::Checks::ContainerMoved.new(project.repository, user, 'http', 'foo/baz')
      project_moved.add_message

      expect(subject).to include(build_basic_message(project_moved.message))
    end
  end

  context 'with new project data' do
    it 'returns new project message on the response' do
      project_created = Gitlab::Checks::ProjectCreated.new(project.repository, user, 'http')
      project_created.add_message

      expect(subject).to include(build_basic_message(project_created.message))
    end
  end

  describe '#process_mr_push_options' do
    context 'when repository belongs to a snippet' do
      context 'with PersonalSnippet' do
        let(:repository) { personal_snippet.repository }

        it 'returns an error message' do
          result = service.process_mr_push_options(push_options, changes)

          expect(result).to match('Push options are only supported for projects')
        end
      end

      context 'with ProjectSnippet' do
        let(:repository) { project_snippet.repository }

        it 'returns an error message' do
          result = service.process_mr_push_options(push_options, changes)

          expect(result).to match('Push options are only supported for projects')
        end
      end
    end
  end

  describe '#merge_request_urls' do
    context 'when repository belongs to a snippet' do
      context 'with PersonalSnippet' do
        let(:repository) { personal_snippet.repository }

        it 'returns an empty array' do
          expect(service.merge_request_urls).to be_empty
        end
      end

      context 'with ProjectSnippet' do
        let(:repository) { project_snippet.repository }

        it 'returns an empty array' do
          expect(service.merge_request_urls).to be_empty
        end
      end
    end
  end

  def build_alert_message(message)
    { 'type' => 'alert', 'message' => message }
  end

  def build_basic_message(message)
    { 'type' => 'basic', 'message' => message }
  end

  def has_alert_messages?(messages)
    messages.any? do |message|
      message['type'] == 'alert'
    end
  end
end


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

class PreviewMarkdownService < BaseService
  def execute
    text, commands = explain_quick_actions(params[:text])
    users = find_user_references(text)
    suggestions = find_suggestions(text)

    success(
      text: text,
      users: users,
      suggestions: suggestions,
      commands: commands.join('<br>')
    )
  end

  private

  def quick_action_types
    %w[Issue MergeRequest Commit WorkItem]
  end

  def explain_quick_actions(text)
    return text, [] unless quick_action_types.include?(target_type)

    quick_actions_service = QuickActions::InterpretService.new(project, current_user)
    quick_actions_service.explain(text, find_commands_target, keep_actions: params[:render_quick_actions])
  end

  def find_user_references(text)
    extractor = Gitlab::ReferenceExtractor.new(project, current_user)
    extractor.analyze(text, author: current_user)
    extractor.users.map(&:username)
  end

  def find_suggestions(text)
    return [] unless preview_sugestions?

    position = Gitlab::Diff::Position.new(new_path: params[:file_path],
                                          new_line: params[:line].to_i,
                                          base_sha: params[:base_sha],
                                          head_sha: params[:head_sha],
                                          start_sha: params[:start_sha])

    Gitlab::Diff::SuggestionsParser.parse(text, position: position,
                                                project: project,
                                                supports_suggestion: params[:preview_suggestions])
  end

  def preview_sugestions?
    params[:preview_suggestions] &&
      target_type == 'MergeRequest' &&
      Ability.allowed?(current_user, :download_code, project)
  end

  def find_commands_target
    QuickActions::TargetService
      .new(project, current_user, group: params[:group])
      .execute(target_type, target_id)
  end

  def target_type
    params[:target_type]
  end

  def target_id
    params[:target_id]
  end
end

PreviewMarkdownService.prepend_mod_with('PreviewMarkdownService')

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe PreviewMarkdownService, feature_category: :team_planning do
  let(:user) { create(:user) }
  let(:project) { create(:project, :repository) }

  before do
    project.add_developer(user)
  end

  describe 'user references' do
    let(:params) { { text: "Take a look #{user.to_reference}" } }
    let(:service) { described_class.new(project, user, params) }

    it 'returns users referenced in text' do
      result = service.execute

      expect(result[:users]).to eq [user.username]
    end
  end

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

    let(:text) { "```suggestion\nfoo\n```" }
    let(:params) do
      suggestion_params.merge(
        text: text,
        target_type: 'MergeRequest',
        target_id: merge_request.iid
      )
    end

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

    context 'when preview markdown param is present' do
      let(:path) { "files/ruby/popen.rb" }
      let(:line) { 10 }
      let(:diff_refs) { merge_request.diff_refs }

      let(:suggestion_params) do
        {
          preview_suggestions: true,
          file_path: path,
          line: line,
          base_sha: diff_refs.base_sha,
          start_sha: diff_refs.start_sha,
          head_sha: diff_refs.head_sha
        }
      end

      it 'returns suggestions referenced in text' do
        position = Gitlab::Diff::Position.new(new_path: path, new_line: line, diff_refs: diff_refs)

        expect(Gitlab::Diff::SuggestionsParser)
          .to receive(:parse)
          .with(
            text,
            position: position,
            project: merge_request.project,
            supports_suggestion: true
          )
          .and_call_original

        result = service.execute

        expect(result[:suggestions]).to all(be_a(Gitlab::Diff::Suggestion))
      end

      context 'when user is not authorized' do
        let(:another_user) { create(:user) }
        let(:service) { described_class.new(project, another_user, params) }

        before do
          project.add_guest(another_user)
        end

        it 'returns no suggestions' do
          result = service.execute

          expect(result[:suggestions]).to be_empty
        end
      end
    end

    context 'when preview markdown param is not present' do
      let(:suggestion_params) do
        {
          preview_suggestions: false
        }
      end

      it 'returns suggestions referenced in text' do
        result = service.execute

        expect(result[:suggestions]).to eq([])
      end
    end
  end

  context 'new note with quick actions' do
    let(:issue) { create(:issue, project: project) }
    let(:params) do
      {
        text: "Please do it\n/assign #{user.to_reference}",
        target_type: 'Issue',
        target_id: issue.id
      }
    end

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

    it 'removes quick actions from text' do
      result = service.execute

      expect(result[:text]).to eq 'Please do it'
    end

    context 'when render_quick_actions' do
      it 'keeps quick actions' do
        params[:render_quick_actions] = true

        result = service.execute

        expect(result[:text]).to eq "Please do it\n\n/assign #{user.to_reference}"
      end
    end

    it 'explains quick actions effect' do
      result = service.execute

      expect(result[:commands]).to eq "Assigns #{user.to_reference}."
    end
  end

  context 'merge request description' do
    let(:params) do
      {
        text: "My work\n/estimate 2y",
        target_type: 'MergeRequest'
      }
    end

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

    it 'removes quick actions from text' do
      result = service.execute

      expect(result[:text]).to eq 'My work'
    end

    it 'explains quick actions effect' do
      result = service.execute

      expect(result[:commands]).to eq 'Sets time estimate to 2y.'
    end
  end

  context 'commit description' do
    let(:project) { create(:project, :repository) }
    let(:commit) { project.commit }
    let(:params) do
      {
        text: "My work\n/tag v1.2.3 Stable release",
        target_type: 'Commit',
        target_id: commit.id
      }
    end

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

    it 'removes quick actions from text' do
      result = service.execute

      expect(result[:text]).to eq 'My work'
    end

    it 'explains quick actions effect' do
      result = service.execute

      expect(result[:commands]).to eq 'Tags this commit to v1.2.3 with "Stable release".'
    end
  end

  context 'note with multiple quick actions' do
    let(:issue) { create(:issue, project: project) }
    let(:params) do
      {
        text: "/confidential\n/due 2001-12-31\n/estimate 2y\n/assign #{user.to_reference}",
        target_type: 'Issue',
        target_id: issue.id
      }
    end

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

    it 'renders quick actions on multiple lines' do
      result = service.execute

      expect(result[:commands]).to eq "Makes this issue confidential.
Sets the due date to Dec 31, 2001.
" \
        "Sets time estimate to 2y.
Assigns #{user.to_reference}."
    end
  end

  context 'work item quick action types' do
    let(:work_item) { create(:work_item, :task, project: project) }
    let(:params) do
      {
        text: "/title new title",
        target_type: 'WorkItem',
        target_id: work_item.iid
      }
    end

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

    it 'renders the quick action preview' do
      expect(result[:commands]).to eq "Changes the title to \"new title\"."
    end
  end
end


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

module ProtectedBranches
  class CacheService < ProtectedBranches::BaseService
    CACHE_ROOT_KEY = 'cache:gitlab:protected_branch'
    TTL_UNSET = -1
    CACHE_EXPIRE_IN = 1.day
    CACHE_LIMIT = 1000

    def fetch(ref_name, dry_run: false, &block)
      record = OpenSSL::Digest::SHA256.hexdigest(ref_name)

      with_redis do |redis|
        cached_result = redis.hget(redis_key, record)

        if cached_result.nil?
          metrics.increment_cache_miss
        else
          metrics.increment_cache_hit

          decoded_result = Gitlab::Redis::Boolean.decode(cached_result)
        end

        # If we're dry-running, don't break because we need to check against
        # the real value to ensure the cache is working properly.
        # If the result is nil we'll need to run the block, so don't break yet.
        break decoded_result unless dry_run || decoded_result.nil?

        calculated_value = metrics.observe_cache_generation(&block)

        check_and_log_discrepancy(decoded_result, calculated_value, ref_name) if dry_run

        redis.hset(redis_key, record, Gitlab::Redis::Boolean.encode(calculated_value))

        # We don't want to extend cache expiration time
        if redis.ttl(redis_key) == TTL_UNSET
          redis.expire(redis_key, CACHE_EXPIRE_IN)
        end

        # If the cache record has too many elements, then something went wrong and
        # it's better to drop the cache key.
        if redis.hlen(redis_key) > CACHE_LIMIT
          redis.unlink(redis_key)
        end

        calculated_value
      end
    end

    def refresh
      with_redis { |redis| redis.unlink(redis_key) }
    end

    private

    def with_redis(&block)
      Gitlab::Redis::Cache.with(&block) # rubocop:disable CodeReuse/ActiveRecord
    end

    def check_and_log_discrepancy(cached_value, real_value, ref_name)
      return if cached_value.nil?
      return if cached_value == real_value

      encoded_ref_name = Gitlab::EncodingHelper.encode_utf8_with_replacement_character(ref_name)

      log_error(
        'class' => self.class.name,
        'message' => "Cache mismatch '#{encoded_ref_name}': cached value: #{cached_value}, real value: #{real_value}",
        'record_class' => project_or_group.class.name,
        'record_id' => project_or_group.id,
        'record_path' => project_or_group.full_path
      )
    end

    def redis_key
      group = project_or_group.is_a?(Group) ? project_or_group : project_or_group.group
      @redis_key ||= if allow_protected_branches_for_group?(group)
                       [CACHE_ROOT_KEY, project_or_group.class.name, project_or_group.id].join(':')
                     else
                       [CACHE_ROOT_KEY, project_or_group.id].join(':')
                     end
    end

    def allow_protected_branches_for_group?(group)
      Feature.enabled?(:group_protected_branches, group) ||
        Feature.enabled?(:allow_protected_branches_for_group, group)
    end

    def metrics
      @metrics ||= Gitlab::Cache::Metrics.new(cache_metadata)
    end

    def cache_metadata
      Gitlab::Cache::Metadata.new(
        cache_identifier: "#{self.class}#fetch",
        feature_category: :source_code_management,
        backing_resource: :cpu
      )
    end
  end
end

```

Response:
# frozen_string_literal: true
# rubocop:disable Style/RedundantFetchBlock
#
require 'spec_helper'

RSpec.describe ProtectedBranches::CacheService, :clean_gitlab_redis_cache, feature_category: :compliance_management do
  shared_examples 'execute with entity' do
    subject(:service) { described_class.new(entity, user) }

    let(:immediate_expiration) { 0 }

    describe '#fetch' do
      it 'caches the value' do
        expect(service.fetch('main') { true }).to eq(true)
        expect(service.fetch('not-found') { false }).to eq(false)

        # Uses cached values
        expect(service.fetch('main') { false }).to eq(true)
        expect(service.fetch('not-found') { true }).to eq(false)
      end

      it 'sets expiry on the key' do
        stub_const("#{described_class.name}::CACHE_EXPIRE_IN", immediate_expiration)

        expect(service.fetch('main') { true }).to eq(true)
        expect(service.fetch('not-found') { false }).to eq(false)

        expect(service.fetch('main') { false }).to eq(false)
        expect(service.fetch('not-found') { true }).to eq(true)
      end

      it 'does not set an expiry on the key after the hash is already created' do
        expect(service.fetch('main') { true }).to eq(true)

        stub_const("#{described_class.name}::CACHE_EXPIRE_IN", immediate_expiration)

        expect(service.fetch('not-found') { false }).to eq(false)

        expect(service.fetch('main') { false }).to eq(true)
        expect(service.fetch('not-found') { true }).to eq(false)
      end

      context 'when CACHE_LIMIT is exceeded' do
        before do
          stub_const("#{described_class.name}::CACHE_LIMIT", 2)
        end

        it 'recreates cache' do
          expect(service.fetch('main') { true }).to eq(true)
          expect(service.fetch('not-found') { false }).to eq(false)

          # Uses cached values
          expect(service.fetch('main') { false }).to eq(true)
          expect(service.fetch('not-found') { true }).to eq(false)

          # Overflow
          expect(service.fetch('new-branch') { true }).to eq(true)

          # Refreshes values
          expect(service.fetch('main') { false }).to eq(false)
          expect(service.fetch('not-found') { true }).to eq(true)
        end
      end

      context 'when dry_run is on' do
        it 'does not use cached value' do
          expect(service.fetch('main', dry_run: true) { true }).to eq(true)
          expect(service.fetch('main', dry_run: true) { false }).to eq(false)
        end

        context 'when cache mismatch' do
          it 'logs an error' do
            expect(service.fetch('main', dry_run: true) { true }).to eq(true)

            expect(Gitlab::AppLogger).to receive(:error).with(
              {
                'class' => described_class.name,
                'message' => /Cache mismatch/,
                'record_class' => entity.class.name,
                'record_id' => entity.id,
                'record_path' => entity.full_path
              }
            )

            expect(service.fetch('main', dry_run: true) { false }).to eq(false)
          end
        end

        context 'when cache matches' do
          it 'does not log an error' do
            expect(service.fetch('main', dry_run: true) { true }).to eq(true)

            expect(Gitlab::AppLogger).not_to receive(:error)

            expect(service.fetch('main', dry_run: true) { true }).to eq(true)
          end
        end
      end
    end

    describe '#refresh' do
      it 'clears cached values' do
        expect(service.fetch('main') { true }).to eq(true)
        expect(service.fetch('not-found') { false }).to eq(false)

        service.refresh

        # Recreates cache
        expect(service.fetch('main') { false }).to eq(false)
        expect(service.fetch('not-found') { true }).to eq(true)
      end
    end

    describe 'metrics' do
      it 'records hit ratio metrics' do
        expect_next_instance_of(Gitlab::Cache::Metrics) do |metrics|
          expect(metrics).to receive(:increment_cache_miss).once
          expect(metrics).to receive(:increment_cache_hit).exactly(4).times
        end

        5.times { service.fetch('main') { true } }
      end
    end
  end

  context 'with entity project' do
    let_it_be_with_reload(:entity) { create(:project) }
    let(:user) { entity.first_owner }

    it_behaves_like 'execute with entity'
  end

  context 'with entity group' do
    let_it_be_with_reload(:entity) { create(:group) }
    let_it_be_with_reload(:user) { create(:user) }

    before do
      entity.add_owner(user)
    end

    context 'when feature flag enabled' do
      it_behaves_like 'execute with entity'
    end

    context 'when feature flag disabled' do
      before do
        stub_feature_flags(group_protected_branches: false)
        stub_feature_flags(allow_protected_branches_for_group: false)
      end

      it_behaves_like 'execute with entity'
    end
  end
end
# rubocop:enable Style/RedundantFetchBlock


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

module ProtectedBranches
  class DestroyService < ProtectedBranches::BaseService
    def execute(protected_branch)
      raise Gitlab::Access::AccessDeniedError unless can?(current_user, :destroy_protected_branch, protected_branch)

      protected_branch.destroy.tap do
        refresh_cache
        after_execute
      end
    end
  end
end

ProtectedBranches::DestroyService.prepend_mod

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe ProtectedBranches::DestroyService, feature_category: :compliance_management do
  shared_examples 'execute with entity' do
    subject(:service) { described_class.new(entity, user) }

    describe '#execute' do
      it 'destroys a protected branch' do
        service.execute(protected_branch)

        expect(protected_branch).to be_destroyed
      end

      it 'refreshes the cache' do
        expect_next_instance_of(ProtectedBranches::CacheService) do |cache_service|
          expect(cache_service).to receive(:refresh)
        end

        service.execute(protected_branch)
      end

      context 'when a policy restricts rule deletion' do
        it "prevents deletion of the protected branch rule" do
          disallow(:destroy_protected_branch, protected_branch)

          expect do
            service.execute(protected_branch)
          end.to raise_error(Gitlab::Access::AccessDeniedError)
        end
      end
    end
  end

  context 'with entity project' do
    let_it_be_with_reload(:entity) { create(:project) }
    let!(:protected_branch) { create(:protected_branch, project: entity) }
    let(:user) { entity.first_owner }

    it_behaves_like 'execute with entity'
  end

  context 'with entity group' do
    let_it_be_with_reload(:entity) { create(:group) }
    let_it_be_with_reload(:user) { create(:user) }
    let!(:protected_branch) { create(:protected_branch, group: entity, project: nil) }

    before do
      allow(Ability).to receive(:allowed?).with(user, :destroy_protected_branch, protected_branch).and_return(true)
    end

    it_behaves_like 'execute with entity'
  end

  def disallow(ability, protected_branch)
    allow(Ability).to receive(:allowed?).and_call_original
    allow(Ability).to receive(:allowed?).with(user, ability, protected_branch).and_return(false)
  end
end


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

module ProtectedBranches
  class UpdateService < ProtectedBranches::BaseService
    def execute(protected_branch)
      raise Gitlab::Access::AccessDeniedError unless can?(current_user, :update_protected_branch, protected_branch)

      old_merge_access_levels = protected_branch.merge_access_levels.map(&:clone)
      old_push_access_levels = protected_branch.push_access_levels.map(&:clone)

      if protected_branch.update(params)
        after_execute(protected_branch: protected_branch, old_merge_access_levels: old_merge_access_levels, old_push_access_levels: old_push_access_levels)

        refresh_cache
      end

      protected_branch
    end
  end
end

ProtectedBranches::UpdateService.prepend_mod

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe ProtectedBranches::UpdateService, feature_category: :compliance_management do
  shared_examples 'execute with entity' do
    let(:params) { { name: new_name } }

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

    describe '#execute' do
      let(:new_name) { 'new protected branch name' }
      let(:result) { service.execute(protected_branch) }

      it 'updates a protected branch' do
        expect(result.reload.name).to eq(params[:name])
      end

      it 'refreshes the cache' do
        expect_next_instance_of(ProtectedBranches::CacheService) do |cache_service|
          expect(cache_service).to receive(:refresh)
        end

        result
      end

      context 'when updating name of a protected branch to one that contains HTML tags' do
        let(:new_name) { 'foo<b>bar<\b>' }
        let(:result) { service.execute(protected_branch) }

        it 'updates a protected branch' do
          expect(result.reload.name).to eq(new_name)
        end
      end

      context 'when a policy restricts rule update' do
        it "prevents update of the protected branch rule" do
          disallow(:update_protected_branch, protected_branch)

          expect { service.execute(protected_branch) }.to raise_error(Gitlab::Access::AccessDeniedError)
        end
      end
    end
  end

  context 'with entity project' do
    let_it_be_with_reload(:entity) { create(:project) }
    let!(:protected_branch) { create(:protected_branch, project: entity) }
    let(:user) { entity.first_owner }

    it_behaves_like 'execute with entity'
  end

  context 'with entity group' do
    let_it_be_with_reload(:entity) { create(:group) }
    let_it_be_with_reload(:user) { create(:user) }
    let!(:protected_branch) { create(:protected_branch, group: entity, project: nil) }

    before do
      allow(Ability).to receive(:allowed?).with(user, :update_protected_branch, protected_branch).and_return(true)
    end

    it_behaves_like 'execute with entity'
  end

  def disallow(ability, protected_branch)
    allow(Ability).to receive(:allowed?).and_call_original
    allow(Ability).to receive(:allowed?).with(user, ability, protected_branch).and_return(false)
  end
end


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

module ProtectedBranches
  class CreateService < ProtectedBranches::BaseService
    def execute(skip_authorization: false)
      raise Gitlab::Access::AccessDeniedError unless skip_authorization || authorized?

      save_protected_branch

      refresh_cache

      protected_branch
    end

    def authorized?
      can?(current_user, :create_protected_branch, protected_branch)
    end

    private

    def save_protected_branch
      protected_branch.save
    end

    def protected_branch
      @protected_branch ||= project_or_group.protected_branches.new(params)
    end
  end
end

ProtectedBranches::CreateService.prepend_mod

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe ProtectedBranches::CreateService, feature_category: :compliance_management do
  shared_examples 'execute with entity' do
    let(:params) do
      {
        name: name,
        merge_access_levels_attributes: [{ access_level: Gitlab::Access::MAINTAINER }],
        push_access_levels_attributes: [{ access_level: Gitlab::Access::MAINTAINER }]
      }
    end

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

    describe '#execute' do
      let(:name) { 'master' }
      let(:group_cache_service_double) { instance_double(ProtectedBranches::CacheService) }
      let(:project_cache_service_double) { instance_double(ProtectedBranches::CacheService) }

      it 'creates a new protected branch' do
        expect { service.execute }.to change(ProtectedBranch, :count).by(1)
        expect(entity.protected_branches.last.push_access_levels.map(&:access_level)).to match_array([Gitlab::Access::MAINTAINER])
        expect(entity.protected_branches.last.merge_access_levels.map(&:access_level)).to match_array([Gitlab::Access::MAINTAINER])
      end

      it 'refreshes the cache' do
        expect(ProtectedBranches::CacheService).to receive(:new).with(entity, user, params).and_return(group_cache_service_double)
        expect(group_cache_service_double).to receive(:refresh)

        if entity.is_a?(Group)
          expect(ProtectedBranches::CacheService).to receive(:new).with(project, user, params).and_return(project_cache_service_double)
          expect(project_cache_service_double).to receive(:refresh)
        end

        service.execute
      end

      context 'when protecting a branch with a name that contains HTML tags' do
        let(:name) { 'foo<b>bar<\b>' }

        it 'creates a new protected branch' do
          expect { service.execute }.to change(ProtectedBranch, :count).by(1)
          expect(entity.protected_branches.last.name).to eq(name)
        end
      end

      context 'when a policy restricts rule creation' do
        it "prevents creation of the protected branch rule" do
          disallow(:create_protected_branch, an_instance_of(ProtectedBranch))

          expect do
            service.execute
          end.to raise_error(Gitlab::Access::AccessDeniedError)
        end

        it 'creates a new protected branch if we skip authorization step' do
          expect { service.execute(skip_authorization: true) }.to change(ProtectedBranch, :count).by(1)
        end
      end
    end
  end

  context 'with entity project' do
    let_it_be_with_reload(:entity) { create(:project) }
    let(:user) { entity.first_owner }

    it_behaves_like 'execute with entity'
  end

  context 'with entity group' do
    let_it_be_with_reload(:project) { create(:project, :in_group) }
    let_it_be_with_reload(:entity) { project.group }
    let_it_be_with_reload(:user) { create(:user) }

    before do
      allow(Ability).to receive(:allowed?).with(user, :create_protected_branch, instance_of(ProtectedBranch)).and_return(true)
    end

    it_behaves_like 'execute with entity'
  end

  def disallow(ability, protected_branch)
    allow(Ability).to receive(:allowed?).and_call_original
    allow(Ability).to receive(:allowed?).with(user, ability, protected_branch).and_return(false)
  end
end


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

module ProtectedBranches
  class ApiService < ProtectedBranches::BaseService
    def create
      ::ProtectedBranches::CreateService.new(project_or_group, @current_user, protected_branch_params).execute
    end

    def update(protected_branch)
      ::ProtectedBranches::UpdateService.new(project_or_group, @current_user,
protected_branch_params(with_defaults: false)).execute(protected_branch)
    end

    private

    def protected_branch_params(with_defaults: true)
      params.slice(*attributes).merge(
        {
          push_access_levels_attributes: access_level_attributes(:push, with_defaults),
          merge_access_levels_attributes: access_level_attributes(:merge, with_defaults)
        }
      )
    end

    def access_level_attributes(type, with_defaults)
      ::ProtectedRefs::AccessLevelParams.new(
        type,
        params,
        with_defaults: with_defaults
      ).access_levels
    end

    def attributes
      [:name, :allow_force_push]
    end
  end
end

ProtectedBranches::ApiService.prepend_mod

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe ProtectedBranches::ApiService, feature_category: :compliance_management do
  shared_examples 'execute with entity' do
    it 'creates a protected branch with prefilled defaults' do
      expect(::ProtectedBranches::CreateService).to receive(:new).with(
        entity,
        user,
        hash_including(
          push_access_levels_attributes: [{ access_level: Gitlab::Access::MAINTAINER }],
          merge_access_levels_attributes: [{ access_level: Gitlab::Access::MAINTAINER }]
        )
      ).and_call_original

      expect(described_class.new(entity, user, { name: 'new name' }).create).to be_valid
    end

    it 'updates a protected branch without prefilled defaults' do
      expect(::ProtectedBranches::UpdateService).to receive(:new).with(
        entity,
        user,
        hash_including(
          push_access_levels_attributes: [],
          merge_access_levels_attributes: []
        )
      ).and_call_original

      expect do
        expect(described_class.new(entity, user, { name: 'new name' }).update(protected_branch)).to be_valid
      end.not_to change { protected_branch.reload.allow_force_push }
    end
  end

  context 'with entity project' do
    let_it_be_with_reload(:entity) { create(:project) }
    let_it_be_with_reload(:protected_branch) { create(:protected_branch, project: entity, allow_force_push: true) }
    let(:user) { entity.first_owner }

    it_behaves_like 'execute with entity'
  end

  context 'with entity group' do
    let_it_be_with_reload(:entity) { create(:group) }
    let_it_be_with_reload(:user) { create(:user) }
    let_it_be_with_reload(:protected_branch) do
      create(:protected_branch, group: entity, project: nil, allow_force_push: true)
    end

    before do
      allow(Ability).to receive(:allowed?).with(user, :update_protected_branch, protected_branch).and_return(true)
      allow(Ability)
        .to receive(:allowed?)
        .with(user, :create_protected_branch, instance_of(ProtectedBranch))
        .and_return(true)
    end

    it_behaves_like 'execute with entity'
  end
end


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

module AuditEvents
  class BuildService
    # Handle missing attributes
    MissingAttributeError = Class.new(StandardError)

    # @raise [MissingAttributeError] when required attributes are blank
    #
    # @return [BuildService]
    def initialize(
      author:, scope:, target:, message:,
      created_at: DateTime.current, additional_details: {}, ip_address: nil, target_details: nil)
      raise MissingAttributeError, "author" if author.blank?
      raise MissingAttributeError, "scope" if scope.blank?
      raise MissingAttributeError, "target" if target.blank?
      raise MissingAttributeError, "message" if message.blank?

      @author = build_author(author)
      @scope = scope
      @target = build_target(target)
      @ip_address = ip_address || build_ip_address
      @message = build_message(message)
      @created_at = created_at
      @additional_details = additional_details
      @target_details = target_details
    end

    # Create an instance of AuditEvent
    #
    # @return [AuditEvent]
    def execute
      AuditEvent.new(payload)
    end

    private

    def payload
      base_payload.merge(details: base_details_payload)
    end

    def base_payload
      {
        author_id: @author.id,
        author_name: @author.name,
        entity_id: @scope.id,
        entity_type: @scope.class.name,
        created_at: @created_at
      }
    end

    def base_details_payload
      @additional_details.merge({
                                  author_name: @author.name,
                                  author_class: @author.class.name,
                                  target_id: @target.id,
                                  target_type: @target.type,
                                  target_details: @target_details || @target.details,
                                  custom_message: @message
                                })
    end

    def build_author(author)
      author.id = -2 if author.instance_of? DeployToken
      author.id = -3 if author.instance_of? DeployKey

      author
    end

    def build_target(target)
      return target if target.is_a? ::Gitlab::Audit::NullTarget

      ::Gitlab::Audit::Target.new(target)
    end

    def build_message(message)
      message
    end

    def build_ip_address
      Gitlab::RequestContext.instance.client_ip || @author.current_sign_in_ip
    end
  end
end

AuditEvents::BuildService.prepend_mod_with('AuditEvents::BuildService')

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe AuditEvents::BuildService, feature_category: :audit_events do
  let(:author) { build_stubbed(:author, current_sign_in_ip: '127.0.0.1') }
  let(:deploy_token) { build_stubbed(:deploy_token, user: author) }
  let(:scope) { build_stubbed(:group) }
  let(:target) { build_stubbed(:project) }
  let(:ip_address) { '192.168.8.8' }
  let(:message) { 'Added an interesting field from project Gotham' }
  let(:additional_details) { { action: :custom } }

  subject(:service) do
    described_class.new(
      author: author,
      scope: scope,
      target: target,
      message: message,
      additional_details: additional_details,
      ip_address: ip_address
    )
  end

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

    before do
      allow(Gitlab::RequestContext.instance).to receive(:client_ip).and_return(ip_address)
    end

    it 'sets correct attributes', :aggregate_failures do
      freeze_time do
        expect(event).to have_attributes(
          author_id: author.id,
          author_name: author.name,
          entity_id: scope.id,
          entity_type: scope.class.name)

        expect(event.details).to eq(
          author_name: author.name,
          author_class: author.class.name,
          target_id: target.id,
          target_type: target.class.name,
          target_details: target.name,
          custom_message: message,
          action: :custom)

        expect(event.ip_address).to be_nil
        expect(event.created_at).to eq(DateTime.current)
      end
    end

    context 'when IP address is not provided' do
      let(:ip_address) { nil }

      it 'uses author current_sign_in_ip' do
        expect(event.ip_address).to be_nil
      end
    end

    context 'when overriding target details' do
      subject(:service) do
        described_class.new(
          author: author,
          scope: scope,
          target: target,
          message: message,
          target_details: "This is my target details"
        )
      end

      it 'uses correct target details' do
        expect(event.target_details).to eq("This is my target details")
      end
    end

    context 'when deploy token is passed as author' do
      let(:service) do
        described_class.new(
          author: deploy_token,
          scope: scope,
          target: target,
          message: message
        )
      end

      it 'expect author to be user' do
        expect(event.author_id).to eq(-2)
        expect(event.author_name).to eq(deploy_token.name)
      end
    end

    context 'when deploy key is passed as author' do
      let(:deploy_key) { build_stubbed(:deploy_key, user: author) }

      let(:service) do
        described_class.new(
          author: deploy_key,
          scope: scope,
          target: target,
          message: message
        )
      end

      it 'expect author to be deploy key' do
        expect(event.author_id).to eq(-3)
        expect(event.author_name).to eq(deploy_key.name)
      end
    end

    context 'when author is passed as UnauthenticatedAuthor' do
      let(:service) do
        described_class.new(
          author: ::Gitlab::Audit::UnauthenticatedAuthor.new,
          scope: scope,
          target: target,
          message: message
        )
      end

      it 'sets author as unauthenticated user' do
        expect(event.author).to be_an_instance_of(::Gitlab::Audit::UnauthenticatedAuthor)
        expect(event.author_name).to eq('An unauthenticated user')
      end
    end

    context 'when attributes are missing' do
      context 'when author is missing' do
        let(:author) { nil }

        it { expect { service }.to raise_error(described_class::MissingAttributeError, "author") }
      end

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

        it { expect { service }.to raise_error(described_class::MissingAttributeError, "scope") }
      end

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

        it { expect { service }.to raise_error(described_class::MissingAttributeError, "target") }
      end

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

        it { expect { service }.to raise_error(described_class::MissingAttributeError, "message") }
      end
    end
  end
end


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

module Ide
  class TerminalConfigService < ::Ide::BaseConfigService
    private

    def success(pass_back = {})
      result = super(pass_back)
      result[:terminal] = config.terminal_value
      result
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Ide::TerminalConfigService, feature_category: :web_ide do
  let_it_be(:project) { create(:project, :repository) }
  let_it_be(:user) { create(:user) }

  let(:sha) { 'sha' }

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

    before do
      project.add_developer(user)

      allow(project.repository).to receive(:blob_data_at).with('sha', anything) do
        config_content
      end
    end

    context 'content is not valid' do
      let(:config_content) { 'invalid content' }

      it 'returns an error' do
        is_expected.to include(
          status: :error,
          message: "Invalid configuration format")
      end
    end

    context 'terminal not defined' do
      let(:config_content) { '{}' }

      it 'returns success' do
        is_expected.to include(
          status: :success,
          terminal: nil)
      end
    end

    context 'terminal enabled' do
      let(:config_content) { 'terminal: {}' }

      it 'returns success' do
        is_expected.to include(
          status: :success,
          terminal: {
            tag_list: [],
            job_variables: [],
            options: { script: ["sleep 60"] }
          })
      end
    end

    context 'custom terminal enabled' do
      let(:config_content) { 'terminal: { before_script: [ls] }' }

      it 'returns success' do
        is_expected.to include(
          status: :success,
          terminal: {
            tag_list: [],
            job_variables: [],
            options: { before_script: ["ls"], script: ["sleep 60"] }
          })
      end
    end
  end
end


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

module Ide
  class SchemasConfigService < ::Ide::BaseConfigService
    PREDEFINED_SCHEMAS = [{
      uri: 'https://json.schemastore.org/gitlab-ci',
      match: ['*.gitlab-ci.yml']
    }].freeze

    def execute
      schema = predefined_schema_for(params[:filename]) || {}
      success(schema: schema)
    rescue StandardError => e
      error(e.message)
    end

    private

    def find_schema(filename, schemas)
      match_flags = ::File::FNM_DOTMATCH | ::File::FNM_PATHNAME

      schemas.each do |schema|
        match = schema[:match].any? { |pattern| ::File.fnmatch?(pattern, filename, match_flags) }

        return Gitlab::Json.parse(get_cached(schema[:uri])) if match
      end

      nil
    end

    def predefined_schema_for(filename)
      find_schema(filename, predefined_schemas)
    end

    def predefined_schemas
      PREDEFINED_SCHEMAS
    end

    def get_cached(url)
      Rails.cache.fetch("services:ide:schema:#{url}", expires_in: 1.day) do
        Gitlab::HTTP.get(url).body
      end
    end
  end
end

Ide::SchemasConfigService.prepend_mod_with('Ide::SchemasConfigService')

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Ide::SchemasConfigService, feature_category: :web_ide do
  let_it_be(:project) { create(:project, :repository) }
  let_it_be(:user) { create(:user) }

  let(:filename) { 'sample.yml' }
  let(:schema_content) { double(body: '{"title":"Sample schema"}') }

  describe '#execute' do
    before do
      project.add_developer(user)

      allow(Gitlab::HTTP).to receive(:get).with(anything) do
        schema_content
      end
    end

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

    context 'when no predefined schema exists for the given filename', unless: Gitlab.ee? do
      it 'returns an empty object' do
        is_expected.to include(
          status: :success,
          schema: {})
      end
    end

    context 'when a predefined schema exists for the given filename' do
      let(:filename) { '.gitlab-ci.yml' }

      it 'uses predefined schema matches' do
        expect(Gitlab::HTTP).to receive(:get).with('https://json.schemastore.org/gitlab-ci')
        expect(subject[:schema]['title']).to eq "Sample schema"
      end
    end
  end
end


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

module Ide
  class BaseConfigService < ::BaseService
    ValidationError = Class.new(StandardError)

    WEBIDE_CONFIG_FILE = '.gitlab/.gitlab-webide.yml'

    attr_reader :config, :config_content

    def execute
      check_access_and_load_config!

      success
    rescue ValidationError => e
      error(e.message)
    end

    protected

    def check_access_and_load_config!
      check_access!
      load_config_content!
      load_config!
    end

    private

    def check_access!
      unless can?(current_user, :download_code, project)
        raise ValidationError, 'Insufficient permissions to read configuration'
      end
    end

    def load_config_content!
      @config_content = webide_yaml_from_repo

      unless config_content
        raise ValidationError, "Failed to load Web IDE config file '#{WEBIDE_CONFIG_FILE}' for #{params[:sha]}"
      end
    end

    def load_config!
      @config = Gitlab::WebIde::Config.new(config_content)

      unless @config.valid?
        raise ValidationError, @config.errors.first
      end
    rescue Gitlab::WebIde::Config::ConfigError => e
      raise ValidationError, e.message
    end

    def webide_yaml_from_repo
      gitlab_webide_yml_for(params[:sha])
    rescue GRPC::NotFound, GRPC::Internal
      nil
    end

    def gitlab_webide_yml_for(sha)
      project.repository.blob_data_at(sha, WEBIDE_CONFIG_FILE)
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Ide::BaseConfigService, feature_category: :web_ide do
  let_it_be(:project) { create(:project, :repository) }
  let_it_be(:user) { create(:user) }

  let(:sha) { 'sha' }

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

    context 'when insufficient permission' do
      it 'returns an error' do
        is_expected.to include(
          status: :error,
          message: 'Insufficient permissions to read configuration')
      end
    end

    context 'for developer' do
      before do
        project.add_developer(user)
      end

      context 'when file is missing' do
        it 'returns an error' do
          is_expected.to include(
            status: :error,
            message: "Failed to load Web IDE config file '.gitlab/.gitlab-webide.yml' for sha")
        end
      end

      context 'when file is present' do
        before do
          allow(project.repository).to receive(:blob_data_at).with('sha', anything) do
            config_content
          end
        end

        context 'content is not valid' do
          let(:config_content) { 'invalid content' }

          it 'returns an error' do
            is_expected.to include(
              status: :error,
              message: "Invalid configuration format")
          end
        end
      end
    end
  end
end


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

module Commits
  class CommitPatchService < CreateService
    # Requires:
    # - project: `Project` to be committed into
    # - user: `User` that will be the committer
    # - params:
    #   - branch_name: `String` the branch that will be committed into
    #   - start_branch: `String` the branch that will be started from
    #   - patches: `Gitlab::Git::Patches::Collection` that contains the patches
    def initialize(*args)
      super

      @patches = Gitlab::Git::Patches::Collection.new(Array(params[:patches]))
    end

    private

    def new_branch?
      !repository.branch_exists?(@branch_name)
    end

    def create_commit!
      if @start_branch && new_branch?
        prepare_branch!
      end

      Gitlab::Git::Patches::CommitPatches
        .new(current_user, project.repository, @branch_name, @patches)
        .commit
    end

    def prepare_branch!
      branch_result = ::Branches::CreateService.new(project, current_user)
                        .execute(@branch_name, @start_branch)

      if branch_result[:status] != :success
        raise ChangeError, branch_result[:message]
      end
    end

    # Overridden from the Commits::CreateService, to skip some validations we
    # don't need:
    # - validate_on_branch!
    #   Not needed, the patches are applied on top of HEAD if the branch did not
    #   exist
    # - validate_branch_existence!
    #   Not needed because we continue applying patches on the branch if it
    #   already existed, and create it if it did not exist.
    def validate!
      validate_patches!
      validate_new_branch_name! if new_branch?
      validate_permissions!
    end

    def validate_patches!
      raise_error("Patches are too big") unless @patches.valid_size?
    end
  end
end

```

Response:
# frozen_string_literal: true
require 'spec_helper'

RSpec.describe Commits::CommitPatchService, feature_category: :source_code_management do
  describe '#execute' do
    let(:patches) do
      patches_folder = Rails.root.join('spec/fixtures/patchfiles')
      content_1 = File.read(File.join(patches_folder, "0001-This-does-not-apply-to-the-feature-branch.patch"))
      content_2 = File.read(File.join(patches_folder, "0001-A-commit-from-a-patch.patch"))

      [content_1, content_2]
    end

    let(:user) { project.creator }
    let(:branch_name) { 'branch-with-patches' }
    let(:project) { create(:project, :repository) }
    let(:start_branch) { nil }
    let(:params) { { branch_name: branch_name, patches: patches, start_branch: start_branch } }

    subject(:service) do
      described_class.new(project, user, params)
    end

    it 'returns a successful result' do
      result = service.execute

      branch = project.repository.find_branch(branch_name)

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

    it 'is based off HEAD when no start ref is passed' do
      service.execute

      merge_base = project.repository.merge_base(project.repository.root_ref, branch_name)

      expect(merge_base).to eq(project.repository.commit('HEAD').sha)
    end

    context 'when specifying a different start branch' do
      let(:start_branch) { 'with-codeowners' }

      it 'is based of the correct branch' do
        service.execute

        merge_base = project.repository.merge_base(start_branch, branch_name)

        expect(merge_base).to eq(project.repository.commit(start_branch).sha)
      end
    end

    shared_examples 'an error response' do |expected_message|
      it 'returns the correct error' do
        result = service.execute

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

    context 'when the user does not have access' do
      let(:user) { create(:user) }

      it_behaves_like 'an error response', 'You are not allowed to push into this branch'
    end

    context 'when the patches are not valid' do
      let(:patches) { "a" * 2.1.megabytes }

      it_behaves_like 'an error response', 'Patches are too big'
    end

    context 'when the new branch name is invalid' do
      let(:branch_name) { 'HEAD' }

      it_behaves_like 'an error response', 'Branch name is invalid'
    end

    context 'when the patches do not apply' do
      let(:branch_name) { 'feature' }

      it_behaves_like 'an error response', 'Patch failed at'
    end

    context 'when specifying a non existent start branch' do
      let(:start_branch) { 'does-not-exist' }

      it_behaves_like 'an error response', 'Failed to create branch'
    end
  end
end


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

module Commits
  class CherryPickService < ChangeService
    def initialize(*args)
      super

      @start_project = params[:target_project] || @project
      @source_project = params[:source_project] || @project
    end

    def create_commit!
      Gitlab::Git::CrossRepo.new(@project.repository, @source_project.repository).execute(@commit.id) do
        commit_change(:cherry_pick).tap do |sha|
          track_mr_picking(sha)
        end
      end
    end

    private

    def track_mr_picking(pick_sha)
      merge_request = project.merge_requests.by_merge_commit_sha(@commit.sha).first
      return unless merge_request

      ::SystemNotes::MergeRequestsService.new(
        noteable: merge_request,
        project: project,
        author: current_user
      ).picked_into_branch(@branch_name, pick_sha)
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Commits::CherryPickService, feature_category: :source_code_management do
  let(:project) { create(:project, :repository) }
  # *   ddd0f15ae83993f5cb66a927a28673882e99100b (HEAD -> master, origin/master, origin/HEAD) Merge branch 'po-fix-test-en
  # |\
  # | * 2d1db523e11e777e49377cfb22d368deec3f0793 Correct test_env.rb path for adding branch
  # |/
  # *   1e292f8fedd741b75372e19097c76d327140c312 Merge branch 'cherry-pick-ce369011' into 'master'

  let_it_be(:merge_commit_sha) { 'ddd0f15ae83993f5cb66a927a28673882e99100b' }
  let_it_be(:merge_base_sha)   { '1e292f8fedd741b75372e19097c76d327140c312' }
  let_it_be(:branch_name)      { 'stable' }

  let(:repository) { project.repository }
  let(:commit) { project.commit }
  let(:user) { create(:user) }

  before do
    project.add_maintainer(user)

    repository.add_branch(user, branch_name, merge_base_sha)
  end

  def cherry_pick(sha, branch_name, message: nil)
    commit = project.commit(sha)

    described_class.new(
      project,
      user,
      commit: commit,
      start_branch: branch_name,
      branch_name: branch_name,
      message: message
    ).execute
  end

  describe '#execute' do
    shared_examples 'successful cherry-pick' do
      it 'picks the commit into the branch' do
        result = cherry_pick(merge_commit_sha, branch_name)
        expect(result[:status]).to eq(:success), result[:message]

        head = repository.find_branch(branch_name).target
        expect(head).not_to eq(merge_base_sha)
      end

      it 'supports a custom commit message' do
        result = cherry_pick(merge_commit_sha, branch_name, message: 'foo')
        branch = repository.find_branch(branch_name)

        expect(result[:status]).to eq(:success)
        expect(branch.dereferenced_target.message).to eq('foo')
      end
    end

    it_behaves_like 'successful cherry-pick'

    context 'when picking a merge-request' do
      let!(:merge_request) { create(:merge_request, :simple, :merged, author: user, source_project: project, merge_commit_sha: merge_commit_sha) }

      it_behaves_like 'successful cherry-pick'

      it 'adds a system note' do
        result = cherry_pick(merge_commit_sha, branch_name)

        mr_notes = find_cherry_pick_notes(merge_request)
        expect(mr_notes.length).to eq(1)
        expect(mr_notes[0].commit_id).to eq(result[:result])
      end
    end

    def find_cherry_pick_notes(noteable)
      noteable
        .notes
        .joins(:system_note_metadata)
        .where(system_note_metadata: { action: 'cherry_pick' })
    end
  end
end


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

module Commits
  class TagService < BaseService
    def execute(commit)
      unless params[:tag_name]
        return error('Missing parameter tag_name')
      end

      tag_name = params[:tag_name]
      message = params[:tag_message]

      result = Tags::CreateService
        .new(commit.project, current_user)
        .execute(tag_name, commit.sha, message)

      if result[:status] == :success
        tag = result[:tag]
        SystemNoteService.tag_commit(commit, commit.project, current_user, tag.name)
      end

      result
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Commits::TagService, feature_category: :source_code_management do
  let(:project) { create(:project, :repository) }
  let(:user) { create(:user) }

  let(:commit) { project.commit }

  before do
    project.add_maintainer(user)
  end

  describe '#execute' do
    let(:service) { described_class.new(project, user, opts) }

    shared_examples 'tag failure' do
      it 'returns a hash with the :error status' do
        result = service.execute(commit)

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

      it 'does not add a system note' do
        service.execute(commit)

        description_notes = find_notes('tag')
        expect(description_notes).to be_empty
      end
    end

    def find_notes(action)
      commit
        .notes
        .joins(:system_note_metadata)
        .where(system_note_metadata: { action: action })
    end

    context 'valid params' do
      let(:opts) do
        {
          tag_name: 'v1.2.3',
          tag_message: 'Release'
        }
      end

      def find_notes(action)
        commit
          .notes
          .joins(:system_note_metadata)
          .where(system_note_metadata: { action: action })
      end

      context 'when tagging succeeds' do
        it 'returns a hash with the :success status and created tag' do
          result = service.execute(commit)

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

          tag = result[:tag]
          expect(tag.name).to eq(opts[:tag_name])
          expect(tag.message).to eq(opts[:tag_message])
        end

        it 'adds a system note' do
          service.execute(commit)

          description_notes = find_notes('tag')
          expect(description_notes.length).to eq(1)
        end
      end

      context 'when tagging fails' do
        let(:tag_error) { 'GitLab: You are not allowed to push code to this project.' }

        before do
          tag_stub = instance_double(Tags::CreateService)
          allow(Tags::CreateService).to receive(:new).and_return(tag_stub)
          allow(tag_stub).to receive(:execute).and_return({
            status: :error, message: tag_error
          })
        end

        it_behaves_like 'tag failure' do
          let(:error_message) { tag_error }
        end
      end
    end

    context 'invalid params' do
      let(:opts) do
        {}
      end

      it_behaves_like 'tag failure' do
        let(:error_message) { 'Missing parameter tag_name' }
      end
    end
  end
end


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

module ImportCsv
  class BaseService
    include Gitlab::Utils::StrongMemoize

    def initialize(user, project, csv_io)
      @user = user
      @project = project
      @csv_io = csv_io
      @results = { success: 0, error_lines: [], parse_error: false, preprocess_errors: {} }
    end

    PreprocessError = Class.new(StandardError)

    def execute
      process_csv
      email_results_to_user

      results
    end

    def email_results_to_user
      raise NotImplementedError
    end

    private

    attr_reader :user, :project, :csv_io, :results

    def attributes_for(row)
      raise NotImplementedError
    end

    def validate_headers_presence!(headers)
      raise NotImplementedError
    end

    def create_object_class
      raise NotImplementedError
    end

    def validate_structure!
      header_line = csv_data.lines.first
      raise CSV::MalformedCSVError.new('File is empty, no headers found', 1) if header_line.blank?

      validate_headers_presence!(header_line)
      detect_col_sep
    end

    def preprocess!
      # any logic can be added in subclasses if needed
      # hence just a no-op rather than NotImplementedError
    end

    def process_csv
      validate_structure!
      preprocess!

      with_csv_lines.each do |row, line_no|
        attributes = attributes_for(row)

        if create_object(attributes)&.persisted?
          results[:success] += 1
        else
          results[:error_lines].push(line_no)
        end
      end
    rescue ArgumentError, CSV::MalformedCSVError => e
      results[:parse_error] = true
      results[:error_lines].push(e.line_number) if e.respond_to?(:line_number)
    rescue PreprocessError
      results[:parse_error] = false
    end

    def with_csv_lines
      CSV.new(
        csv_data,
        col_sep: detect_col_sep,
        headers: true,
        header_converters: :symbol
      ).each.with_index(2)
    end

    def csv_data
      @csv_io.open(&:read).force_encoding(Encoding::UTF_8)
    end
    strong_memoize_attr :csv_data

    def detect_col_sep
      header = csv_data.lines.first

      if header.include?(",")
        ","
      elsif header.include?(";")
        ";"
      elsif header.include?("\t")
        "\t"
      else
        raise CSV::MalformedCSVError.new('Invalid CSV format', 1)
      end
    end
    strong_memoize_attr :detect_col_sep

    def create_object(attributes)
      # default_params can be extracted into a method if we need
      # to support creation of objects that belongs to groups.
      default_params = { container: project,
                         current_user: user,
                         params: attributes,
                         perform_spam_check: false }

      create_service = create_object_class.new(**default_params.merge(extra_create_service_params))

      create_service.execute_without_rate_limiting
    end

    # Overidden in subclasses to support specific parameters
    def extra_create_service_params
      {}
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe ImportCsv::BaseService, feature_category: :importers do
  let_it_be(:user) { create(:user) }
  let_it_be(:project) { create(:project) }
  let_it_be(:csv_io) { double }

  subject { described_class.new(user, project, csv_io) }

  shared_examples 'abstract method' do |method, args|
    it "raises NotImplemented error when #{method} is called" do
      if args
        expect { subject.send(method, args) }.to raise_error(NotImplementedError)
      else
        expect { subject.send(method) }.to raise_error(NotImplementedError)
      end
    end
  end

  it_behaves_like 'abstract method', :email_results_to_user
  it_behaves_like 'abstract method', :attributes_for, "any"
  it_behaves_like 'abstract method', :validate_headers_presence!, "any"
  it_behaves_like 'abstract method', :create_object_class

  context 'when given a class' do
    let(:importer_klass) do
      Class.new(described_class) do
        def attributes_for(row)
          { title: row[:title] }
        end

        def validate_headers_presence!(headers)
          raise CSV::MalformedCSVError.new("Missing required headers", 1) unless headers.present?
        end

        def create_object_class
          Class.new
        end

        def email_results_to_user
          # no-op
        end
      end
    end

    let(:service) do
      uploader = FileUploader.new(project)
      uploader.store!(file)

      importer_klass.new(user, project, uploader)
    end

    subject { service.execute }

    it_behaves_like 'correctly handles invalid files'

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

      let(:file) { double }

      before do
        allow(service).to receive_message_chain('csv_data.lines.first').and_return(header)
      end

      where(:sep_character, :valid) do
        '&' | false
        '?' | false
        ';' | true
        ',' | true
        "\t" | true
      end

      with_them do
        let(:header) { "Name#{sep_character}email" }

        it 'responds appropriately' do
          if valid
            expect(service.send(:detect_col_sep)).to eq sep_character
          else
            expect { service.send(:detect_col_sep) }.to raise_error(CSV::MalformedCSVError)
          end
        end
      end
    end
  end
end