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

module Issuable
  module ImportCsv
    class BaseService < ::ImportCsv::BaseService
      extend ::Gitlab::Utils::Override

      private

      override :attributes_for
      def attributes_for(row)
        {
          title: row[:title],
          description: row[:description],
          due_date: row[:due_date],
          milestone_id: find_milestone_by_title(row[:milestone])
        }
      end

      override :validate_headers_presence!
      def validate_headers_presence!(headers)
        headers.downcase! if headers
        return if headers && headers.include?('title') && headers.include?('description')

        raise CSV::MalformedCSVError.new('Invalid CSV format - missing required headers.', 1)
      end

      def preprocess!
        preprocess_milestones!

        raise PreprocessError if results[:preprocess_errors].any?
      end

      def preprocess_milestones!
        # Pre-Process Milestone if header is present
        return unless csv_data.lines.first.downcase.include?('milestone')

        provided_titles = with_csv_lines.filter_map { |row| row[:milestone]&.strip }.uniq
        result = ::ImportCsv::PreprocessMilestonesService.new(user, project, provided_titles).execute
        @available_milestones = result.payload
        return if result.success?

        # collate errors here and throw errors
        results[:preprocess_errors][:milestone_errors] = result.payload
      end

      def find_milestone_by_title(title)
        return unless title

        @available_milestones.find { |milestone| milestone.title == title.to_s.strip } if @available_milestones
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

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

  let(:importer_klass) do
    Class.new(described_class) do
      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 }

  describe '#preprocess_milestones' do
    let(:utility_class) { ImportCsv::PreprocessMilestonesService }
    let(:file) { fixture_file_upload('spec/fixtures/csv_missing_milestones.csv') }
    let(:mocked_object) { double }

    before do
      allow(service).to receive(:create_object).and_return(mocked_object)
      allow(mocked_object).to receive(:persisted?).and_return(true)
    end

    context 'with csv that has milestone heading' do
      before do
        allow(utility_class).to receive(:new).and_return(utility_class)
        allow(utility_class).to receive(:execute).and_return(ServiceResponse.success)
      end

      it 'calls PreprocessMilestonesService' do
        subject
        expect(utility_class).to have_received(:new)
      end

      it 'calls PreprocessMilestonesService with unique milestone titles' do
        subject
        expect(utility_class).to have_received(:new).with(user, project, %w[15.10 10.1])
        expect(utility_class).to have_received(:execute)
      end
    end

    context 'with csv that does not have milestone heading' do
      let(:file) { fixture_file_upload('spec/fixtures/work_items_valid_types.csv') }

      before do
        allow(utility_class).to receive(:new).and_return(utility_class)
      end

      it 'does not call PreprocessMilestonesService' do
        subject
        expect(utility_class).not_to have_received(:new)
      end
    end

    context 'when one or more milestones do not exist' do
      it 'returns the expected error in results payload' do
        results = subject

        expect(results[:success]).to eq(0)
        expect(results[:preprocess_errors]).to match({
          milestone_errors: { missing: { header: 'Milestone', titles: %w[15.10 10.1] } }
        })
      end
    end

    context 'when all milestones exist' do
      let!(:group_milestone) { create(:milestone, group: group, title: '10.1') }
      let!(:project_milestone) { create(:milestone, project: project, title: '15.10') }

      it 'returns a successful response' do
        results = subject

        expect(results[:preprocess_errors]).to be_empty
        expect(results[:success]).to eq(4)
      end
    end
  end
end


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

module Issuable
  module Callbacks
    class Milestone < Base
      ALLOWED_PARAMS = %i[milestone milestone_id skip_milestone_email].freeze

      def after_initialize
        params[:milestone_id] = nil if excluded_in_new_type?
        return unless params.key?(:milestone_id) && has_permission?(:"set_#{issuable.to_ability_name}_metadata")

        @old_milestone = issuable.milestone

        if params[:milestone_id].blank? || params[:milestone_id].to_s == IssuableFinder::Params::NONE
          issuable.milestone = nil

          return
        end

        resource_group = issuable.project&.group || issuable.try(:namespace)
        project_ids = [issuable.project&.id].compact

        milestone = MilestonesFinder.new({
          project_ids: project_ids,
          group_ids: resource_group&.self_and_ancestors&.select(:id),
          ids: [params[:milestone_id]]
        }).execute.first

        issuable.milestone = milestone if milestone
      end

      def after_update_commit
        return unless issuable.previous_changes.include?('milestone_id')

        update_usage_data_counters
        send_milestone_change_notification

        GraphqlTriggers.issuable_milestone_updated(issuable)
      end

      def after_save_commit
        return unless issuable.previous_changes.include?('milestone_id')

        invalidate_milestone_counters
      end

      private

      def invalidate_milestone_counters
        [@old_milestone, issuable.milestone].compact.each do |milestone|
          case issuable
          when Issue
            ::Milestones::ClosedIssuesCountService.new(milestone).delete_cache
            ::Milestones::IssuesCountService.new(milestone).delete_cache
          when MergeRequest
            ::Milestones::MergeRequestsCountService.new(milestone).delete_cache
          end
        end
      end

      def update_usage_data_counters
        return unless issuable.is_a?(MergeRequest)

        Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter
          .track_milestone_changed_action(user: current_user)
      end

      def send_milestone_change_notification
        return if params[:skip_milestone_email]

        notification_service = NotificationService.new.async

        if issuable.milestone.nil?
          notification_service.removed_milestone(issuable, current_user)
        else
          notification_service.changed_milestone(issuable, issuable.milestone, current_user)
        end
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Issuable::Callbacks::Milestone, feature_category: :team_planning do
  let_it_be(:group) { create(:group) }
  let_it_be(:project) { create(:project, :private, group: group) }
  let_it_be(:project_milestone) { create(:milestone, project: project) }
  let_it_be(:group_milestone) { create(:milestone, group: group) }
  let_it_be(:reporter) do
    create(:user).tap { |u| project.add_reporter(u) }
  end

  let(:issuable) { build(:issue, project: project) }
  let(:current_user) { reporter }
  let(:params) { { milestone_id: project_milestone.id } }
  let(:callback) { described_class.new(issuable: issuable, current_user: current_user, params: params) }

  describe '#after_initialize' do
    it "sets the issuable's milestone" do
      expect { callback.after_initialize }.to change { issuable.milestone }.from(nil).to(project_milestone)
    end

    context 'when assigning a group milestone' do
      let(:params) { { milestone_id: group_milestone.id } }

      it "sets the issuable's milestone" do
        expect { callback.after_initialize }.to change { issuable.milestone }.from(nil).to(group_milestone)
      end
    end

    context 'when assigning a group milestone outside the project ancestors' do
      let(:another_group_milestone) { create(:milestone, group: create(:group)) }
      let(:params) { { milestone_id: another_group_milestone.id } }

      it "does not change the issuable's milestone" do
        expect { callback.after_initialize }.not_to change { issuable.milestone }
      end
    end

    context 'when user is not allowed to set issuable metadata' do
      let(:current_user) { create(:user) }

      it "does not change the issuable's milestone" do
        expect { callback.after_initialize }.not_to change { issuable.milestone }
      end
    end

    context 'when unsetting a milestone' do
      let(:issuable) { create(:issue, project: project, milestone: project_milestone) }

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

        it "unsets the issuable's milestone" do
          expect { callback.after_initialize }.to change { issuable.milestone }.from(project_milestone).to(nil)
        end
      end

      context 'when milestone_id is an empty string' do
        let(:params) { { milestone_id: '' } }

        it "unsets the issuable's milestone" do
          expect { callback.after_initialize }.to change { issuable.milestone }.from(project_milestone).to(nil)
        end
      end

      context 'when milestone_id is 0' do
        let(:params) { { milestone_id: '0' } }

        it "unsets the issuable's milestone" do
          expect { callback.after_initialize }.to change { issuable.milestone }.from(project_milestone).to(nil)
        end
      end

      context "when milestone_id is '0'" do
        let(:params) { { milestone_id: 0 } }

        it "unsets the issuable's milestone" do
          expect { callback.after_initialize }.to change { issuable.milestone }.from(project_milestone).to(nil)
        end
      end

      context 'when milestone_id is not given' do
        let(:params) { {} }

        it "does not unset the issuable's milestone" do
          expect { callback.after_initialize }.not_to change { issuable.milestone }
        end
      end

      context 'when new type does not support milestones' do
        let(:params) { { excluded_in_new_type: true } }

        it "unsets the issuable's milestone" do
          expect { callback.after_initialize }.to change { issuable.milestone }.from(project_milestone).to(nil)
        end
      end
    end
  end
end


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

module Namespaces
  class StatisticsRefresherService
    RefresherError = Class.new(StandardError)

    def execute(root_namespace)
      root_namespace = root_namespace.root_ancestor # just in case the true root isn't passed
      root_storage_statistics = find_or_create_root_storage_statistics(root_namespace.id)

      root_storage_statistics.recalculate!
    rescue ActiveRecord::ActiveRecordError => e
      raise RefresherError, e.message
    end

    private

    def find_or_create_root_storage_statistics(root_namespace_id)
      Namespace::RootStorageStatistics
        .safe_find_or_create_by!(namespace_id: root_namespace_id)
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Namespaces::StatisticsRefresherService, '#execute', feature_category: :groups_and_projects do
  let(:group) { create(:group) }
  let(:subgroup) { create(:group, parent: group) }
  let(:projects) { create_list(:project, 5, namespace: group) }
  let(:service) { described_class.new }

  context 'without a root storage statistics relation' do
    it 'creates one' do
      expect do
        service.execute(group)
      end.to change(Namespace::RootStorageStatistics, :count).by(1)

      expect(group.reload.root_storage_statistics).to be_present
    end

    it 'recalculate the namespace statistics' do
      expect_next_instance_of(Namespace::RootStorageStatistics) do |instance|
        expect(instance).to receive(:recalculate!).once
      end

      service.execute(group)
    end

    context 'when given a subgroup' do
      it 'does not create statistics for the subgroup' do
        service.execute(subgroup)

        expect(subgroup.reload.root_storage_statistics).not_to be_present
      end
    end
  end

  context 'with a root storage statistics relation', :sidekiq_might_not_need_inline do
    before do
      Namespace::AggregationSchedule.safe_find_or_create_by!(namespace_id: group.id)
    end

    it 'does not create one' do
      expect do
        service.execute(group)
      end.not_to change(Namespace::RootStorageStatistics, :count)
    end

    it 'recalculate the namespace statistics' do
      expect(Namespace::RootStorageStatistics)
        .to receive(:safe_find_or_create_by!).with({ namespace_id: group.id })
        .and_return(group.root_storage_statistics)

      service.execute(group)
    end

    context 'when given a subgroup' do
      it "recalculates the root namespace's statistics" do
        expect(Namespace::RootStorageStatistics)
          .to receive(:safe_find_or_create_by!).with({ namespace_id: group.id })
          .and_return(group.root_storage_statistics)

        service.execute(subgroup)
      end
    end
  end

  context 'when something goes wrong' do
    before do
      allow_next_instance_of(Namespace::RootStorageStatistics) do |instance|
        allow(instance).to receive(:recalculate!).and_raise(ActiveRecord::ActiveRecordError)
      end
    end

    it 'raises RefreshError' do
      expect do
        service.execute(group)
      end.to raise_error(Namespaces::StatisticsRefresherService::RefresherError)
    end
  end
end


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

module Namespaces
  module PackageSettings
    class UpdateService < BaseContainerService
      include Gitlab::Utils::StrongMemoize

      ALLOWED_ATTRIBUTES = %i[maven_duplicates_allowed
                              maven_duplicate_exception_regex
                              generic_duplicates_allowed
                              generic_duplicate_exception_regex
                              maven_package_requests_forwarding
                              nuget_duplicates_allowed
                              nuget_duplicate_exception_regex
                              npm_package_requests_forwarding
                              pypi_package_requests_forwarding
                              lock_maven_package_requests_forwarding
                              lock_npm_package_requests_forwarding
                              lock_pypi_package_requests_forwarding].freeze

      def execute
        return ServiceResponse.error(message: 'Access Denied', http_status: 403) unless allowed?

        if package_settings.update(package_settings_params)
          ServiceResponse.success(payload: { package_settings: package_settings })
        else
          ServiceResponse.error(
            message: package_settings.errors.full_messages.to_sentence || 'Bad request',
            http_status: 400
          )
        end
      end

      private

      def package_settings
        strong_memoize(:package_settings) do
          @container.package_settings
        end
      end

      def allowed?
        Ability.allowed?(current_user, :admin_package, @container)
      end

      def package_settings_params
        @params.slice(*ALLOWED_ATTRIBUTES)
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe ::Namespaces::PackageSettings::UpdateService, feature_category: :package_registry do
  using RSpec::Parameterized::TableSyntax

  let_it_be_with_reload(:namespace) { create(:group) }
  let_it_be(:user) { create(:user) }
  let_it_be(:params) { {} }

  describe '#execute' do
    subject { described_class.new(container: namespace, current_user: user, params: params).execute }

    shared_examples 'returning a success' do
      it 'returns a success' do
        result = subject

        expect(result.payload[:package_settings]).to be_present
        expect(result.success?).to be_truthy
      end
    end

    shared_examples 'returning an error' do |message, http_status|
      it 'returns an error' do
        result = subject

        expect(result.message).to eq(message)
        expect(result.status).to eq(:error)
        expect(result.http_status).to eq(http_status)
      end
    end

    shared_examples 'updating the namespace package setting' do
      it_behaves_like 'updating the namespace package setting attributes',
        from: {
          maven_duplicates_allowed: true,
          maven_duplicate_exception_regex: 'SNAPSHOT',
          generic_duplicates_allowed: true,
          generic_duplicate_exception_regex: 'foo',
          nuget_duplicates_allowed: true,
          nuget_duplicate_exception_regex: 'foo',
          maven_package_requests_forwarding: true,
          lock_maven_package_requests_forwarding: false,
          npm_package_requests_forwarding: nil,
          lock_npm_package_requests_forwarding: false,
          pypi_package_requests_forwarding: nil,
          lock_pypi_package_requests_forwarding: false
        }, to: {
          maven_duplicates_allowed: false,
          maven_duplicate_exception_regex: 'RELEASE',
          generic_duplicates_allowed: false,
          generic_duplicate_exception_regex: 'bar',
          nuget_duplicates_allowed: false,
          nuget_duplicate_exception_regex: 'bar',
          maven_package_requests_forwarding: true,
          lock_maven_package_requests_forwarding: true,
          npm_package_requests_forwarding: true,
          lock_npm_package_requests_forwarding: true,
          pypi_package_requests_forwarding: true,
          lock_pypi_package_requests_forwarding: true
        }

      it_behaves_like 'returning a success'

      context 'with invalid params' do
        let_it_be(:params) { { maven_duplicates_allowed: nil } }

        it_behaves_like 'not creating the namespace package setting'

        it "doesn't update the maven_duplicates_allowed" do
          expect { subject }
            .not_to change { package_settings.reload.maven_duplicates_allowed }
        end

        it_behaves_like 'returning an error', 'Maven duplicates allowed is not included in the list', 400
      end
    end

    shared_examples 'denying access to namespace package setting' do
      context 'with existing namespace package setting' do
        it_behaves_like 'not creating the namespace package setting'

        it_behaves_like 'returning an error', 'Access Denied', 403
      end
    end

    # To be removed when raise_group_admin_package_permission_to_owner FF is removed
    shared_examples 'disabling admin_package feature flag' do |action:|
      before do
        stub_feature_flags(raise_group_admin_package_permission_to_owner: false)
      end

      it_behaves_like "#{action} the namespace package setting"
    end

    context 'with existing namespace package setting' do
      let_it_be(:package_settings) { create(:namespace_package_setting, namespace: namespace) }
      let_it_be(:params) do
        {
          maven_duplicates_allowed: false,
          maven_duplicate_exception_regex: 'RELEASE',
          generic_duplicates_allowed: false,
          generic_duplicate_exception_regex: 'bar',
          nuget_duplicates_allowed: false,
          nuget_duplicate_exception_regex: 'bar',
          maven_package_requests_forwarding: true,
          lock_maven_package_requests_forwarding: true,
          npm_package_requests_forwarding: true,
          lock_npm_package_requests_forwarding: true,
          pypi_package_requests_forwarding: true,
          lock_pypi_package_requests_forwarding: true
        }
      end

      where(:user_role, :shared_examples_name) do
        :owner      | 'updating the namespace package setting'
        :maintainer | 'denying access to namespace package setting'
        :developer  | 'denying access to namespace package setting'
        :reporter   | 'denying access to namespace package setting'
        :guest      | 'denying access to namespace package setting'
        :anonymous  | 'denying access to namespace package setting'
      end

      with_them do
        before do
          namespace.send("add_#{user_role}", user) unless user_role == :anonymous
        end

        it_behaves_like params[:shared_examples_name]
        it_behaves_like 'disabling admin_package feature flag', action: :updating if params[:user_role] == :maintainer
      end
    end

    context 'without existing namespace package setting' do
      let_it_be(:package_settings) { namespace.package_settings }

      where(:user_role, :shared_examples_name) do
        :owner      | 'creating the namespace package setting'
        :maintainer | 'denying access to namespace package setting'
        :developer  | 'denying access to namespace package setting'
        :reporter   | 'denying access to namespace package setting'
        :guest      | 'denying access to namespace package setting'
        :anonymous  | 'denying access to namespace package setting'
      end

      with_them do
        before do
          namespace.send("add_#{user_role}", user) unless user_role == :anonymous
        end

        it_behaves_like params[:shared_examples_name]
        it_behaves_like 'disabling admin_package feature flag', action: :creating if params[:user_role] == :maintainer
      end
    end
  end
end


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

module TestHooks
  class ProjectService < TestHooks::BaseService
    include Integrations::ProjectTestData
    include Gitlab::Utils::StrongMemoize

    attr_writer :project

    def project
      @project ||= hook.project
    end

    private

    def data
      strong_memoize(:data) do
        case trigger
        when 'push_events', 'tag_push_events'
          push_events_data
        when 'note_events'
          note_events_data
        when 'issues_events', 'confidential_issues_events'
          issues_events_data
        when 'merge_requests_events'
          merge_requests_events_data
        when 'job_events'
          job_events_data
        when 'pipeline_events'
          pipeline_events_data
        when 'wiki_page_events'
          wiki_page_events_data
        when 'releases_events'
          releases_events_data
        when 'emoji_events'
          emoji_events_data
        end
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe TestHooks::ProjectService, feature_category: :code_testing do
  include AfterNextHelpers

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

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

    let(:hook) { create(:project_hook, project: project) }
    let(:trigger) { 'not_implemented_events' }
    let(:service) { described_class.new(hook, current_user, trigger) }
    let(:sample_data) { { data: 'sample' } }
    let(:success_result) { { status: :success, http_status: 200, message: 'ok' } }

    it 'allows to set a custom project' do
      project = double
      service.project = project

      expect(service.project).to eq(project)
    end

    context 'hook with not implemented test' do
      it 'returns error message' do
        expect(hook).not_to receive(:execute)
        expect(service.execute).to have_attributes(status: :error, message: 'Testing not available for this hook')
      end
    end

    context 'push_events' do
      let(:trigger) { 'push_events' }
      let(:trigger_key) { :push_hooks }

      it 'executes hook' do
        allow(Gitlab::DataBuilder::Push).to receive(:build_sample).and_return(sample_data)

        expect(hook).to receive(:execute).with(sample_data, trigger_key, force: true).and_return(success_result)
        expect(service.execute).to include(success_result)
      end
    end

    context 'tag_push_events' do
      let(:trigger) { 'tag_push_events' }
      let(:trigger_key) { :tag_push_hooks }

      it 'executes hook' do
        allow(Gitlab::DataBuilder::Push).to receive(:build_sample).and_return(sample_data)

        expect(hook).to receive(:execute).with(sample_data, trigger_key, force: true).and_return(success_result)
        expect(service.execute).to include(success_result)
      end
    end

    context 'note_events' do
      let(:trigger) { 'note_events' }
      let(:trigger_key) { :note_hooks }

      it 'returns error message if not enough data' do
        expect(hook).not_to receive(:execute)
        expect(service.execute).to have_attributes(status: :error, message: 'Ensure the project has notes.')
      end

      it 'executes hook' do
        create(:note, project: project)

        allow(Gitlab::DataBuilder::Note).to receive(:build).and_return(sample_data)
        allow_next(NotesFinder).to receive(:execute).and_return(Note.all)

        expect(hook).to receive(:execute).with(sample_data, trigger_key, force: true).and_return(success_result)
        expect(service.execute).to include(success_result)
      end
    end

    shared_examples_for 'a test webhook that operates on issues' do
      let(:issue) { build(:issue) }

      it 'returns error message if not enough data' do
        expect(hook).not_to receive(:execute)
        expect(service.execute).to have_attributes(status: :error, message: 'Ensure the project has issues.')
      end

      it 'executes hook' do
        allow(issue).to receive(:to_hook_data).and_return(sample_data)
        allow_next(IssuesFinder).to receive(:execute).and_return([issue])

        expect(hook).to receive(:execute).with(sample_data, trigger_key, force: true).and_return(success_result)
        expect(service.execute).to include(success_result)
      end
    end

    context 'issues_events' do
      let(:trigger) { 'issues_events' }
      let(:trigger_key) { :issue_hooks }

      it_behaves_like 'a test webhook that operates on issues'
    end

    context 'confidential_issues_events' do
      let(:trigger) { 'confidential_issues_events' }
      let(:trigger_key) { :confidential_issue_hooks }

      it_behaves_like 'a test webhook that operates on issues'
    end

    context 'merge_requests_events' do
      let(:trigger) { 'merge_requests_events' }
      let(:trigger_key) { :merge_request_hooks }
      let(:merge_request) { build(:merge_request) }

      it 'returns error message if not enough data' do
        expect(hook).not_to receive(:execute)
        expect(service.execute).to have_attributes(status: :error, message: 'Ensure the project has merge requests.')
      end

      it 'executes hook' do
        allow(merge_request).to receive(:to_hook_data).and_return(sample_data)
        allow_next(MergeRequestsFinder).to receive(:execute).and_return([merge_request])

        expect(hook).to receive(:execute).with(sample_data, trigger_key, force: true).and_return(success_result)
        expect(service.execute).to include(success_result)
      end
    end

    context 'job_events' do
      let(:trigger) { 'job_events' }
      let(:trigger_key) { :job_hooks }
      let(:ci_job) { build(:ci_build) }

      it 'returns error message if not enough data' do
        expect(hook).not_to receive(:execute)
        expect(service.execute).to have_attributes(status: :error, message: 'Ensure the project has CI jobs.')
      end

      it 'executes hook' do
        allow(Gitlab::DataBuilder::Build).to receive(:build).and_return(sample_data)
        allow_next(Ci::JobsFinder).to receive(:execute).and_return([ci_job])

        expect(hook).to receive(:execute).with(sample_data, trigger_key, force: true).and_return(success_result)
        expect(service.execute).to include(success_result)
      end
    end

    context 'pipeline_events' do
      let(:trigger) { 'pipeline_events' }
      let(:trigger_key) { :pipeline_hooks }
      let(:pipeline) { build(:ci_empty_pipeline) }

      it 'returns error message if not enough data' do
        expect(hook).not_to receive(:execute)
        expect(service.execute).to have_attributes(status: :error, message: 'Ensure the project has CI pipelines.')
      end

      it 'executes hook' do
        allow(Gitlab::DataBuilder::Pipeline).to receive(:build).and_return(sample_data)
        allow_next(Ci::PipelinesFinder).to receive(:execute).and_return([pipeline])

        expect(hook).to receive(:execute).with(sample_data, trigger_key, force: true).and_return(success_result)
        expect(service.execute).to include(success_result)
      end
    end

    context 'wiki_page_events' do
      let_it_be(:project) { create(:project, :wiki_repo) }

      let(:trigger) { 'wiki_page_events' }
      let(:trigger_key) { :wiki_page_hooks }

      it 'returns error message if wiki disabled' do
        allow(project).to receive(:wiki_enabled?).and_return(false)

        expect(hook).not_to receive(:execute)
        expect(service.execute).to have_attributes(status: :error, message: 'Ensure the wiki is enabled and has pages.')
      end

      it 'returns error message if not enough data' do
        expect(hook).not_to receive(:execute)
        expect(service.execute).to have_attributes(status: :error, message: 'Ensure the wiki is enabled and has pages.')
      end

      it 'executes hook' do
        create(:wiki_page, wiki: project.wiki)
        allow(Gitlab::DataBuilder::WikiPage).to receive(:build).and_return(sample_data)

        expect(hook).to receive(:execute).with(sample_data, trigger_key, force: true).and_return(success_result)
        expect(service.execute).to include(success_result)
      end
    end

    context 'releases_events' do
      let(:trigger) { 'releases_events' }
      let(:trigger_key) { :release_hooks }
      let(:release) { build(:release) }

      it 'returns error message if not enough data' do
        expect(hook).not_to receive(:execute)
        expect(service.execute).to have_attributes(status: :error, message: 'Ensure the project has releases.')
      end

      it 'executes hook' do
        allow(release).to receive(:to_hook_data).and_return(sample_data)
        allow_next(ReleasesFinder).to receive(:execute).and_return([release])

        expect(hook).to receive(:execute).with(sample_data, trigger_key, force: true).and_return(success_result)
        expect(service.execute).to include(success_result)
      end
    end

    context 'emoji' do
      let(:trigger) { 'emoji_events' }
      let(:trigger_key) { :emoji_hooks }

      it 'returns error message if not enough data' do
        expect(hook).not_to receive(:execute)
        expect(service.execute).to have_attributes(status: :error, message: 'Ensure the project has notes.')
      end

      it 'executes hook' do
        note = create(:note)
        allow(project).to receive_message_chain(:notes, :any?).and_return(true)
        allow(project).to receive_message_chain(:notes, :last).and_return(note)
        allow(Gitlab::DataBuilder::Emoji).to receive(:build).with(anything, current_user, 'award')
          .and_return(sample_data)

        expect(hook).to receive(:execute).with(sample_data, trigger_key, force: true).and_return(success_result)
        expect(service.execute).to include(success_result)
      end
    end
  end
end


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

module TestHooks
  class SystemService < TestHooks::BaseService
    include Gitlab::Utils::StrongMemoize

    private

    def data
      strong_memoize(:data) do
        case trigger
        when 'push_events', 'tag_push_events'
          Gitlab::DataBuilder::Push.sample_data
        when 'repository_update_events'
          Gitlab::DataBuilder::Repository.sample_data
        when 'merge_requests_events'
          merge_requests_events_data
        end
      end
    end

    def merge_requests_events_data
      merge_request = MergeRequest.of_projects(current_user.projects.select(:id)).last

      return { error: s_('TestHooks|Ensure one of your projects has merge requests.') } unless merge_request.present?

      merge_request.to_hook_data(current_user)
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe TestHooks::SystemService, feature_category: :code_testing do
  include AfterNextHelpers

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

    let(:hook)    { create(:system_hook) }
    let(:service) { described_class.new(hook, project.first_owner, trigger) }
    let(:success_result) { { status: :success, http_status: 200, message: 'ok' } }

    before do
      allow(Project).to receive(:first).and_return(project)
    end

    context 'hook with not implemented test' do
      let(:trigger) { 'not_implemented_events' }

      it 'returns error message' do
        expect(hook).not_to receive(:execute)
        expect(service.execute).to have_attributes(status: :error, message: 'Testing not available for this hook')
      end
    end

    context 'push_events' do
      let(:trigger) { 'push_events' }
      let(:trigger_key) { :push_hooks }

      it 'executes hook' do
        expect(Gitlab::DataBuilder::Push).to receive(:sample_data).and_call_original

        expect(hook).to receive(:execute).with(Gitlab::DataBuilder::Push::SAMPLE_DATA, trigger_key, force: true).and_return(success_result)
        expect(service.execute).to include(success_result)
      end
    end

    context 'tag_push_events' do
      let(:trigger) { 'tag_push_events' }
      let(:trigger_key) { :tag_push_hooks }

      it 'executes hook' do
        allow(project.repository).to receive(:tags).and_return(['tag'])
        expect(Gitlab::DataBuilder::Push).to receive(:sample_data).and_call_original

        expect(hook).to receive(:execute).with(Gitlab::DataBuilder::Push::SAMPLE_DATA, trigger_key, force: true).and_return(success_result)
        expect(service.execute).to include(success_result)
      end
    end

    context 'repository_update_events' do
      let(:trigger) { 'repository_update_events' }
      let(:trigger_key) { :repository_update_hooks }

      it 'executes hook' do
        expect(Gitlab::DataBuilder::Repository).to receive(:sample_data).and_call_original

        expect(hook).to receive(:execute).with(Gitlab::DataBuilder::Repository::SAMPLE_DATA, trigger_key, force: true).and_return(success_result)
        expect(service.execute).to include(success_result)
      end
    end

    context 'merge_requests_events' do
      let(:trigger) { 'merge_requests_events' }
      let(:trigger_key) { :merge_request_hooks }
      let(:merge_request) { build(:merge_request) }
      let(:sample_data) { { data: 'sample' } }

      it 'returns error message if the user does not have any repository with a merge request' do
        expect(hook).not_to receive(:execute)
        expect(service.execute).to have_attributes(status: :error, message: 'Ensure one of your projects has merge requests.')
      end

      it 'executes hook' do
        expect(MergeRequest).to receive(:of_projects).and_return([merge_request])
        expect(merge_request).to receive(:to_hook_data).and_return(sample_data)
        expect(hook).to receive(:execute).with(sample_data, trigger_key, force: true).and_return(success_result)
        expect(service.execute).to include(success_result)
      end
    end
  end
end


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

# GroupMentionService class
#
# Used for sending group mention notifications
#
# Ex.
#   Integrations::GroupMentionService.new(mentionable, hook_data: data, is_confidential: true).execute
#
module Integrations
  class GroupMentionService
    def initialize(mentionable, hook_data:, is_confidential:)
      @mentionable = mentionable
      @hook_data = hook_data
      @is_confidential = is_confidential
    end

    def execute
      return ServiceResponse.success if mentionable.nil? || hook_data.nil?

      @hook_data = hook_data.clone
      # Fake a "group_mention" object kind so integrations can handle this as a separate class of event
      hook_data[:object_attributes][:object_kind] = hook_data[:object_kind]
      hook_data[:object_kind] = 'group_mention'

      if confidential?
        hook_data[:event_type] = 'group_confidential_mention'
        hook_scope = :group_confidential_mention_hooks
      else
        hook_data[:event_type] = 'group_mention'
        hook_scope = :group_mention_hooks
      end

      groups = mentionable.referenced_groups(mentionable.author)
      groups.each do |group|
        group_hook_data = hook_data.merge(
          mentioned: {
            object_kind: 'group',
            name: group.full_path,
            url: group.web_url
          }
        )
        group.execute_integrations(group_hook_data, hook_scope)
      end

      ServiceResponse.success
    end

    private

    attr_reader :mentionable, :hook_data, :is_confidential

    def confidential?
      return is_confidential if is_confidential.present?

      mentionable.project.visibility_level != Gitlab::VisibilityLevel::PUBLIC
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Integrations::GroupMentionService, feature_category: :integrations do
  subject(:execute) { described_class.new(mentionable, hook_data: hook_data, is_confidential: is_confidential).execute }

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

  before do
    allow(mentionable).to receive(:referenced_groups).with(user).and_return([group])
  end

  shared_examples 'group_mention_hooks' do
    specify do
      expect(group).to receive(:execute_integrations).with(anything, :group_mention_hooks)
      expect(execute).to be_success
    end
  end

  shared_examples 'group_confidential_mention_hooks' do
    specify do
      expect(group).to receive(:execute_integrations).with(anything, :group_confidential_mention_hooks)
      expect(execute).to be_success
    end
  end

  context 'for issue descriptions' do
    let(:hook_data) { mentionable.to_hook_data(user) }
    let(:is_confidential) { mentionable.confidential? }

    context 'in public projects' do
      let_it_be(:project) { create(:project, :public) }

      context 'in public issues' do
        let(:mentionable) do
          create(:issue, confidential: false, project: project, author: user, description: "@#{group.full_path}")
        end

        it_behaves_like 'group_mention_hooks'
      end

      context 'in confidential issues' do
        let(:mentionable) do
          create(:issue, confidential: true, project: project, author: user, description: "@#{group.full_path}")
        end

        it_behaves_like 'group_confidential_mention_hooks'
      end
    end

    context 'in private projects' do
      let_it_be(:project) { create(:project, :private) }

      context 'in public issues' do
        let(:mentionable) do
          create(:issue, confidential: false, project: project, author: user, description: "@#{group.full_path}")
        end

        it_behaves_like 'group_confidential_mention_hooks'
      end

      context 'in confidential issues' do
        let(:mentionable) do
          create(:issue, confidential: true, project: project, author: user, description: "@#{group.full_path}")
        end

        it_behaves_like 'group_confidential_mention_hooks'
      end
    end
  end

  context 'for merge request descriptions' do
    let(:hook_data) { mentionable.to_hook_data(user) }
    let(:is_confidential) { false }
    let(:mentionable) do
      create(:merge_request, source_project: project, target_project: project, author: user,
        description: "@#{group.full_path}")
    end

    context 'in public projects' do
      let_it_be(:project) { create(:project, :public) }

      it_behaves_like 'group_mention_hooks'
    end

    context 'in private projects' do
      let_it_be(:project) { create(:project, :private) }

      it_behaves_like 'group_confidential_mention_hooks'
    end
  end

  context 'for issue notes' do
    let(:hook_data) { Gitlab::DataBuilder::Note.build(mentionable, mentionable.author) }
    let(:is_confidential) { mentionable.confidential?(include_noteable: true) }

    context 'in public projects' do
      let_it_be(:project) { create(:project, :public) }

      context 'in public issues' do
        let(:issue) do
          create(:issue, confidential: false, project: project, author: user, description: "@#{group.full_path}")
        end

        context 'for public notes' do
          let(:mentionable) { create(:note_on_issue, noteable: issue, project: project, author: user) }

          it_behaves_like 'group_mention_hooks'
        end

        context 'for internal notes' do
          let(:mentionable) { create(:note_on_issue, :confidential, noteable: issue, project: project, author: user) }

          it_behaves_like 'group_confidential_mention_hooks'
        end
      end
    end

    context 'in private projects' do
      let_it_be(:project) { create(:project, :private) }

      context 'in public issues' do
        let(:issue) do
          create(:issue, confidential: false, project: project, author: user, description: "@#{group.full_path}")
        end

        context 'for public notes' do
          let(:mentionable) { create(:note_on_issue, noteable: issue, project: project, author: user) }

          it_behaves_like 'group_confidential_mention_hooks'
        end

        context 'for internal notes' do
          let(:mentionable) { create(:note_on_issue, :confidential, noteable: issue, project: project, author: user) }

          it_behaves_like 'group_confidential_mention_hooks'
        end
      end
    end
  end
end


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

module Integrations
  class SlackOptionService
    UnknownOptionError = Class.new(StandardError)

    OPTIONS = {
      'assignee' => SlackOptions::UserSearchHandler,
      'labels' => SlackOptions::LabelSearchHandler
    }.freeze

    def initialize(params)
      @params = params
      @search_type = params.delete(:action_id)
      @selected_value = params.delete(:value)
      @view_id = params.dig(:view, :id)
    end

    def execute
      raise UnknownOptionError, "Unable to handle option: '#{search_type}'" \
        unless option?(search_type)

      handler_class = OPTIONS[search_type]
      handler_class.new(current_user, selected_value, view_id).execute
    end

    private

    def current_user
      ChatNames::FindUserService.new(
        params.dig(:team, :id),
        params.dig(:user, :id)
      ).execute
    end

    def option?(option)
      OPTIONS.key?(option)
    end

    attr_reader :params, :search_type, :selected_value, :view_id
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Integrations::SlackOptionService, feature_category: :integrations do
  describe '#execute' do
    subject(:execute) { described_class.new(params).execute }

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

    let_it_be(:chat_name) do
      create(:chat_name,
        user: user,
        team_id: slack_installation.team_id,
        chat_id: slack_installation.user_id
      )
    end

    let(:params) do
      {
        action_id: action_id,
        view: {
          id: 'VHDFR54DSA'
        },
        value: 'Search value',
        team: {
          id: slack_installation.team_id
        },
        user: {
          id: slack_installation.user_id
        }
      }
    end

    context 'when action_id is assignee' do
      let(:action_id) { 'assignee' }

      it 'executes the user search handler' do
        user_search_handler = described_class::OPTIONS['assignee']

        expect_next_instance_of(user_search_handler, chat_name, 'Search value', 'VHDFR54DSA') do |service|
          expect(service).to receive(:execute).and_return(ServiceResponse.success)
        end

        execute
      end
    end

    context 'when action_id is labels' do
      let(:action_id) { 'labels' }

      it 'executes the label search handler' do
        label_search_handler = described_class::OPTIONS['labels']

        expect_next_instance_of(label_search_handler, chat_name, 'Search value', 'VHDFR54DSA') do |service|
          expect(service).to receive(:execute).and_return(ServiceResponse.success)
        end

        execute
      end
    end

    context 'when action_id is unknown' do
      let(:action_id) { 'foo' }

      it 'raises an error and does not execute a service class' do
        described_class::OPTIONS.each_value do |service_class|
          expect(service_class).not_to receive(:new)
        end

        expect { execute }.to raise_error(described_class::UnknownOptionError)
      end
    end
  end
end


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

# Performs the initial handling of event payloads sent from Slack to GitLab.
# See `API::Integrations::Slack::Events` which calls this service.
module Integrations
  class SlackEventService
    URL_VERIFICATION_EVENT = 'url_verification'

    UnknownEventError = Class.new(StandardError)

    def initialize(params)
      # When receiving URL verification events, params[:type] is 'url_verification'.
      # For all other events we subscribe to, params[:type] is 'event_callback' and
      # the specific type of the event will be in params[:event][:type].
      # Remove both of these from the params before they are passed to the services.
      type = params.delete(:type)
      type = params[:event].delete(:type) if type == 'event_callback'

      @slack_event = type
      @params = params
    end

    def execute
      raise UnknownEventError, "Unable to handle event type: '#{slack_event}'" unless routable_event?

      payload = route_event

      ServiceResponse.success(payload: payload)
    end

    private

    # The `url_verification` slack_event response must be returned to Slack in-request,
    # so for this event we call the service directly instead of through a worker.
    #
    # All other events must be handled asynchronously in order to return a 2xx response
    # immediately to Slack in the request. See https://api.slack.com/apis/connections/events-api.
    def route_in_request?
      slack_event == URL_VERIFICATION_EVENT
    end

    def routable_event?
      route_in_request? || route_to_event_worker?
    end

    def route_to_event_worker?
      SlackEventWorker.event?(slack_event)
    end

    # Returns a payload for the service response.
    def route_event
      return SlackEvents::UrlVerificationService.new(params).execute if route_in_request?

      SlackEventWorker.perform_async(slack_event: slack_event, params: params)

      {}
    end

    attr_reader :slack_event, :params
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Integrations::SlackEventService, feature_category: :integrations do
  describe '#execute' do
    subject(:execute) { described_class.new(params).execute }

    let(:params) do
      {
        type: 'event_callback',
        event: {
          type: 'app_home_opened',
          foo: 'bar'
        }
      }
    end

    it 'queues a worker and returns success response' do
      expect(Integrations::SlackEventWorker).to receive(:perform_async)
        .with(
          {
            slack_event: 'app_home_opened',
            params: {
              event: {
                foo: 'bar'
              }
            }
          }
        )
      expect(execute.payload).to eq({})
      is_expected.to be_success
    end

    context 'when event a url verification request' do
      let(:params) { { type: 'url_verification', foo: 'bar' } }

      it 'executes the service instead of queueing a worker and returns success response' do
        expect(Integrations::SlackEventWorker).not_to receive(:perform_async)
        expect_next_instance_of(Integrations::SlackEvents::UrlVerificationService, { foo: 'bar' }) do |service|
          expect(service).to receive(:execute).and_return({ baz: 'qux' })
        end
        expect(execute.payload).to eq({ baz: 'qux' })
        is_expected.to be_success
      end
    end

    context 'when event is unknown' do
      let(:params) { super().merge(event: { type: 'foo' }) }

      it 'raises an error' do
        expect { execute }.to raise_error(described_class::UnknownEventError)
      end
    end
  end
end


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

module Integrations
  class PropagateService
    BATCH_SIZE = 10_000

    def initialize(integration)
      @integration = integration
    end

    def propagate
      if integration.instance_level?
        update_inherited_integrations
        create_integration_for_groups_without_integration
        create_integration_for_projects_without_integration
      else
        update_inherited_descendant_integrations
        create_integration_for_groups_without_integration_belonging_to_group
        create_integration_for_projects_without_integration_belonging_to_group
      end
    end

    def self.propagate(integration)
      new(integration).propagate
    end

    private

    attr_reader :integration

    def create_integration_for_projects_without_integration
      propagate_integrations(
        Project.without_integration(integration),
        PropagateIntegrationProjectWorker
      )
    end

    def update_inherited_integrations
      propagate_integrations(
        Integration.by_type(integration.type).inherit_from_id(integration.id),
        PropagateIntegrationInheritWorker
      )
    end

    def update_inherited_descendant_integrations
      propagate_integrations(
        Integration.inherited_descendants_from_self_or_ancestors_from(integration),
        PropagateIntegrationInheritDescendantWorker
      )
    end

    def create_integration_for_groups_without_integration
      propagate_integrations(
        Group.without_integration(integration),
        PropagateIntegrationGroupWorker
      )
    end

    def create_integration_for_groups_without_integration_belonging_to_group
      propagate_integrations(
        integration.group.descendants.without_integration(integration),
        PropagateIntegrationGroupWorker
      )
    end

    def create_integration_for_projects_without_integration_belonging_to_group
      propagate_integrations(
        Project.without_integration(integration).in_namespace(integration.group.self_and_descendants),
        PropagateIntegrationProjectWorker
      )
    end

    def propagate_integrations(relation, worker_class)
      relation.each_batch(of: BATCH_SIZE) do |records|
        min_id, max_id = records.pick("MIN(#{relation.table_name}.id), MAX(#{relation.table_name}.id)")
        worker_class.perform_async(integration.id, min_id, max_id)
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Integrations::PropagateService, feature_category: :integrations do
  describe '.propagate' do
    include JiraIntegrationHelpers

    before do
      stub_jira_integration_test
    end

    let(:group) { create(:group) }

    let_it_be(:project) { create(:project) }
    let_it_be(:instance_integration) { create(:jira_integration, :instance) }
    let_it_be(:not_inherited_integration) { create(:jira_integration, project: project) }
    let_it_be(:inherited_integration) do
      create(:jira_integration, project: create(:project), inherit_from_id: instance_integration.id)
    end

    let_it_be(:different_type_inherited_integration) do
      create(:redmine_integration, project: project, inherit_from_id: instance_integration.id)
    end

    context 'with inherited integration' do
      let(:integration) { inherited_integration }

      it 'calls to PropagateIntegrationProjectWorker' do
        expect(PropagateIntegrationInheritWorker).to receive(:perform_async)
          .with(instance_integration.id, inherited_integration.id, inherited_integration.id)

        described_class.propagate(instance_integration)
      end
    end

    context 'with a project without integration' do
      let(:another_project) { create(:project) }

      it 'calls to PropagateIntegrationProjectWorker' do
        expect(PropagateIntegrationProjectWorker).to receive(:perform_async)
          .with(instance_integration.id, another_project.id, another_project.id)

        described_class.propagate(instance_integration)
      end
    end

    context 'with a group without integration' do
      it 'calls to PropagateIntegrationProjectWorker' do
        expect(PropagateIntegrationGroupWorker).to receive(:perform_async)
          .with(instance_integration.id, group.id, group.id)

        described_class.propagate(instance_integration)
      end
    end

    context 'for a group-level integration' do
      let(:group_integration) { create(:jira_integration, :group, group: group) }

      context 'with a project without integration' do
        let(:another_project) { create(:project, group: group) }

        it 'calls to PropagateIntegrationProjectWorker' do
          expect(PropagateIntegrationProjectWorker).to receive(:perform_async)
            .with(group_integration.id, another_project.id, another_project.id)

          described_class.propagate(group_integration)
        end
      end

      context 'with a subgroup without integration' do
        let(:subgroup) { create(:group, parent: group) }

        it 'calls to PropagateIntegrationGroupWorker' do
          expect(PropagateIntegrationGroupWorker).to receive(:perform_async)
            .with(group_integration.id, subgroup.id, subgroup.id)

          described_class.propagate(group_integration)
        end
      end

      context 'with a subgroup with integration' do
        let(:subgroup) { create(:group, parent: group) }
        let(:subgroup_integration) { create(:jira_integration, :group, group: subgroup, inherit_from_id: group_integration.id) }

        it 'calls to PropagateIntegrationInheritDescendantWorker' do
          expect(PropagateIntegrationInheritDescendantWorker).to receive(:perform_async)
            .with(group_integration.id, subgroup_integration.id, subgroup_integration.id)

          described_class.propagate(group_integration)
        end
      end
    end
  end
end


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

module Integrations
  class SlackInteractionService
    UnknownInteractionError = Class.new(StandardError)

    INTERACTIONS = {
      'view_closed' => SlackInteractions::IncidentManagement::IncidentModalClosedService,
      'view_submission' => SlackInteractions::IncidentManagement::IncidentModalSubmitService,
      'block_actions' => SlackInteractions::BlockActionService
    }.freeze

    def initialize(params)
      @interaction_type = params.delete(:type)
      @params = params
    end

    def execute
      raise UnknownInteractionError, "Unable to handle interaction type: '#{interaction_type}'" \
        unless interaction?(interaction_type)

      service_class = INTERACTIONS[interaction_type]
      service_class.new(params).execute

      ServiceResponse.success
    end

    private

    attr_reader :interaction_type, :params

    def interaction?(type)
      INTERACTIONS.key?(type)
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Integrations::SlackInteractionService, feature_category: :integrations do
  describe '#execute' do
    subject(:execute) { described_class.new(params).execute }

    let(:params) do
      {
        type: slack_interaction,
        foo: 'bar'
      }
    end

    context 'when view is closed' do
      let(:slack_interaction) { 'view_closed' }

      it 'executes the correct service' do
        view_closed_service = described_class::INTERACTIONS['view_closed']

        expect_next_instance_of(view_closed_service, { foo: 'bar' }) do |service|
          expect(service).to receive(:execute).and_return(ServiceResponse.success)
        end

        execute
      end
    end

    context 'when view is submitted' do
      let(:slack_interaction) { 'view_submission' }

      it 'executes the submission service' do
        view_submission_service = described_class::INTERACTIONS['view_submission']

        expect_next_instance_of(view_submission_service, { foo: 'bar' }) do |service|
          expect(service).to receive(:execute).and_return(ServiceResponse.success)
        end

        execute
      end
    end

    context 'when block action service is submitted' do
      let(:slack_interaction) { 'block_actions' }

      it 'executes the block actions service' do
        block_action_service = described_class::INTERACTIONS['block_actions']

        expect_next_instance_of(block_action_service, { foo: 'bar' }) do |service|
          expect(service).to receive(:execute).and_return(ServiceResponse.success)
        end

        execute
      end
    end

    context 'when slack_interaction is not known' do
      let(:slack_interaction) { 'foo' }

      it 'raises an error and does not execute a service class' do
        described_class::INTERACTIONS.each_value do |service_class|
          expect(service_class).not_to receive(:new)
        end

        expect { execute }.to raise_error(described_class::UnknownInteractionError)
      end
    end
  end
end


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

module Integrations
  module SlackOptions
    class UserSearchHandler # rubocop:disable Search/NamespacedClass
      include Gitlab::Utils::StrongMemoize

      def initialize(current_user, search_value, view_id)
        @current_user = current_user.user
        @search_value = search_value
        @view_id = view_id
      end

      def execute
        return ServiceResponse.success(payload: []) unless current_user.can?(:read_project_member, project)

        members = MembersFinder.new(project, current_user, params: { search: search_value }).execute

        ServiceResponse.success(payload: build_user_list(members))
      end

      private

      def project
        project_id = SlackInteractions::IncidentManagement::IncidentModalOpenedService
              .cache_read(view_id)

        return unless project_id

        Project.find(project_id)
      end
      strong_memoize_attr :project

      def build_user_list(members)
        return [] unless members

        user_list = members.map do |member|
          {
            text: {
              type: "plain_text",
              text: "#{member.user.name} - #{member.user.username}"
            },
            value: member.user.id.to_s
          }
        end

        {
          options: user_list
        }
      end

      attr_reader :current_user, :search_value, :view_id
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Integrations::SlackOptions::UserSearchHandler, feature_category: :integrations do
  describe '#execute' do
    let_it_be(:project) { create(:project, :private) }
    let_it_be(:current_user) { create(:user) }
    let_it_be(:chat_name) { create(:chat_name, user: current_user) }
    let_it_be(:user1) { create(:user, name: 'Rajendra Kadam') }
    let_it_be(:user2) { create(:user, name: 'Rajesh K') }
    let_it_be(:user3) { create(:user) }
    let_it_be(:view_id) { 'VXHD54DR' }

    let(:search_value) { 'Raj' }

    subject(:execute) { described_class.new(chat_name, search_value, view_id).execute }

    context 'when user has permissions to read project members' do
      before do
        project.add_developer(current_user)
        project.add_guest(user1)
        project.add_reporter(user2)
        project.add_maintainer(user3)
      end

      it 'returns the user matching the search term' do
        expect(Rails.cache).to receive(:read).and_return(project.id)

        members = execute.payload[:options]
        user_names = members.map { |member| member.dig(:text, :text) }

        expect(members.count).to eq(2)
        expect(user_names).to contain_exactly(
          "#{user1.name} - #{user1.username}",
          "#{user2.name} - #{user2.username}"
        )
      end
    end

    context 'when user does not have permissions to read project members' do
      it 'returns empty array' do
        expect(Rails.cache).to receive(:read).and_return(project.id)
        expect(MembersFinder).not_to receive(:execute)

        members = execute.payload

        expect(members).to be_empty
      end
    end
  end
end


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

module Integrations
  module SlackOptions
    class LabelSearchHandler # rubocop:disable Search/NamespacedClass
      include Gitlab::Utils::StrongMemoize

      def initialize(current_user, search_value, view_id)
        @current_user = current_user.user
        @search_value = search_value
        @view_id = view_id
      end

      def execute
        return ServiceResponse.success(payload: []) unless current_user.can?(:read_label, project)

        labels = LabelsFinder.new(
          current_user,
          {
            project: project,
            search: search_value
          }
        ).execute

        ServiceResponse.success(payload: build_label_list(labels))
      end

      private

      def project
        project_id = Integrations::SlackInteractions::IncidentManagement::IncidentModalOpenedService
              .cache_read(view_id)

        return unless project_id

        Project.find(project_id)
      end
      strong_memoize_attr :project

      def build_label_list(labels)
        return [] unless labels

        label_list = labels.map do |label|
          {
            text: {
              type: "plain_text",
              text: label.name
            },
            value: label.id.to_s
          }
        end

        {
          options: label_list
        }
      end

      attr_accessor :current_user, :search_value, :view_id
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Integrations::SlackOptions::LabelSearchHandler, feature_category: :integrations do
  describe '#execute' do
    let_it_be(:group) { create(:group) }
    let_it_be(:project) { create(:project, :private, namespace: group) }
    let_it_be(:current_user) { create(:user) }
    let_it_be(:chat_name) { create(:chat_name, user: current_user) }
    let_it_be(:project_label1) { create(:label, project: project, title: 'Label 1') }
    let_it_be(:project_label2) { create(:label, project: project, title: 'Label 2') }
    let_it_be(:group_label1) { create(:group_label, group: group, title: 'LabelG 1') }
    let_it_be(:group_label2) { create(:group_label, group: group, title: 'glb 2') }
    let_it_be(:view_id) { 'VXHD54DR' }

    let(:search_value) { 'Lab' }

    subject(:execute) { described_class.new(chat_name, search_value, view_id).execute }

    context 'when user has permission to read project and group labels' do
      before do
        allow(Rails.cache).to receive(:read).and_return(project.id)
        project.add_developer(current_user)
      end

      it 'returns the labels matching the search term' do
        labels = execute.payload[:options]
        label_names = labels.map { |label| label.dig(:text, :text) }

        expect(label_names).to contain_exactly(
          project_label1.name,
          project_label2.name,
          group_label1.name
        )
      end
    end

    context 'when user does not have permissions to read project/group labels' do
      it 'returns empty array' do
        expect(LabelsFinder).not_to receive(:execute)

        expect(execute.payload).to be_empty
      end
    end
  end
end


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

module Integrations
  module Test
    class ProjectService < Integrations::Test::BaseService
      include Integrations::ProjectTestData
      include Gitlab::Utils::StrongMemoize

      def project
        strong_memoize(:project) do
          integration.project
        end
      end

      private

      def data
        strong_memoize(:data) do
          case event || integration.default_test_event
          when 'push', 'tag_push'
            push_events_data
          when 'note', 'confidential_note'
            note_events_data
          when 'issue', 'confidential_issue'
            issues_events_data
          when 'merge_request'
            merge_requests_events_data
          when 'job'
            job_events_data
          when 'pipeline'
            pipeline_events_data
          when 'wiki_page'
            wiki_page_events_data
          when 'deployment'
            deployment_events_data
          when 'release'
            releases_events_data
          when 'award_emoji'
            emoji_events_data
          end
        end
      end
    end
  end
end

Integrations::Test::ProjectService.prepend_mod_with('Integrations::Test::ProjectService')

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Integrations::Test::ProjectService, feature_category: :integrations do
  include AfterNextHelpers

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

    let(:integration) { create(:integrations_slack, project: project) }
    let(:user) { project.first_owner }
    let(:event) { nil }
    let(:sample_data) { { data: 'sample' } }
    let(:success_result) { { success: true, result: {} } }

    subject { described_class.new(integration, user, event).execute }

    context 'without event specified' do
      it 'tests the integration with default data' do
        allow(Gitlab::DataBuilder::Push).to receive(:build_sample).and_return(sample_data)

        expect(integration).to receive(:test).with(sample_data).and_return(success_result)
        expect(subject).to eq(success_result)
      end

      context 'with Integrations::PipelinesEmail' do
        let(:integration) { create(:pipelines_email_integration, project: project) }

        it_behaves_like 'tests for integration with pipeline data'
      end
    end

    context 'with event specified' do
      context 'event not supported by integration' do
        let(:integration) { create(:jira_integration, project: project) }
        let(:event) { 'push' }

        it 'returns error message' do
          expect(subject).to include({ status: :error, message: 'Testing not available for this event' })
        end
      end

      context 'push' do
        let(:event) { 'push' }

        it 'executes integration' do
          allow(Gitlab::DataBuilder::Push).to receive(:build_sample).and_return(sample_data)

          expect(integration).to receive(:test).with(sample_data).and_return(success_result)
          expect(subject).to eq(success_result)
        end
      end

      context 'tag_push' do
        let(:event) { 'tag_push' }

        it 'executes integration' do
          allow(Gitlab::DataBuilder::Push).to receive(:build_sample).and_return(sample_data)

          expect(integration).to receive(:test).with(sample_data).and_return(success_result)
          expect(subject).to eq(success_result)
        end
      end

      context 'note' do
        let(:event) { 'note' }

        it 'returns error message if not enough data' do
          expect(integration).not_to receive(:test)
          expect(subject).to include({ status: :error, message: 'Ensure the project has notes.' })
        end

        it 'executes integration' do
          create(:note, project: project)

          allow(Gitlab::DataBuilder::Note).to receive(:build).and_return(sample_data)
          allow_next(NotesFinder).to receive(:execute).and_return(Note.all)

          expect(integration).to receive(:test).with(sample_data).and_return(success_result)
          expect(subject).to eq(success_result)
        end
      end

      shared_examples_for 'a test of an integration that operates on issues' do
        let(:issue) { build(:issue) }

        it 'returns error message if not enough data' do
          expect(integration).not_to receive(:test)
          expect(subject).to include({ status: :error, message: 'Ensure the project has issues.' })
        end

        it 'executes integration' do
          allow(project).to receive(:issues).and_return([issue])
          allow(issue).to receive(:to_hook_data).and_return(sample_data)
          allow_next(IssuesFinder).to receive(:execute).and_return([issue])

          expect(integration).to receive(:test).with(sample_data).and_return(success_result)
          expect(subject).to eq(success_result)
        end
      end

      context 'issue' do
        let(:event) { 'issue' }

        it_behaves_like 'a test of an integration that operates on issues'
      end

      context 'confidential_issue' do
        let(:event) { 'confidential_issue' }

        it_behaves_like 'a test of an integration that operates on issues'
      end

      context 'merge_request' do
        let(:event) { 'merge_request' }
        let(:merge_request) { build(:merge_request) }

        it 'returns error message if not enough data' do
          expect(integration).not_to receive(:test)
          expect(subject).to include({ status: :error, message: 'Ensure the project has merge requests.' })
        end

        it 'executes integration' do
          allow(merge_request).to receive(:to_hook_data).and_return(sample_data)
          allow_next(MergeRequestsFinder).to receive(:execute).and_return([merge_request])

          expect(integration).to receive(:test).with(sample_data).and_return(success_result)
          expect(subject).to include(success_result)
        end
      end

      context 'deployment' do
        let_it_be(:project) { create(:project, :test_repo) }

        let(:deployment) { build(:deployment) }
        let(:event) { 'deployment' }

        it 'returns error message if not enough data' do
          expect(integration).not_to receive(:test)
          expect(subject).to include({ status: :error, message: 'Ensure the project has deployments.' })
        end

        it 'executes integration' do
          allow(Gitlab::DataBuilder::Deployment).to receive(:build).and_return(sample_data)
          allow_next(DeploymentsFinder).to receive(:execute).and_return([deployment])

          expect(integration).to receive(:test).with(sample_data).and_return(success_result)
          expect(subject).to eq(success_result)
        end
      end

      context 'pipeline' do
        let(:event) { 'pipeline' }
        let(:pipeline) { build(:ci_pipeline) }

        it 'returns error message if not enough data' do
          expect(integration).not_to receive(:test)
          expect(subject).to include({ status: :error, message: 'Ensure the project has CI pipelines.' })
        end

        it 'executes integration' do
          allow(Gitlab::DataBuilder::Pipeline).to receive(:build).and_return(sample_data)
          allow_next(Ci::PipelinesFinder).to receive(:execute).and_return([pipeline])

          expect(integration).to receive(:test).with(sample_data).and_return(success_result)
          expect(subject).to eq(success_result)
        end
      end

      context 'wiki_page' do
        let_it_be(:project) { create(:project, :wiki_repo) }

        let(:event) { 'wiki_page' }

        it 'returns error message if wiki disabled' do
          allow(project).to receive(:wiki_enabled?).and_return(false)

          expect(integration).not_to receive(:test)
          expect(subject).to include({ status: :error, message: 'Ensure the wiki is enabled and has pages.' })
        end

        it 'returns error message if not enough data' do
          expect(integration).not_to receive(:test)
          expect(subject).to include({ status: :error, message: 'Ensure the wiki is enabled and has pages.' })
        end

        it 'executes integration' do
          create(:wiki_page, wiki: project.wiki)
          allow(Gitlab::DataBuilder::WikiPage).to receive(:build).and_return(sample_data)

          expect(integration).to receive(:test).with(sample_data).and_return(success_result)
          expect(subject).to eq(success_result)
        end
      end
    end
  end
end


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

# Handles the Slack `app_home_opened` event sent from Slack to GitLab.
# Responds with a POST to the Slack API 'views.publish' method.
#
# See:
# - https://api.slack.com/methods/views.publish
# - https://api.slack.com/events/app_home_opened
module Integrations
  module SlackEvents
    class AppHomeOpenedService
      include Gitlab::Utils::StrongMemoize

      def initialize(params)
        @slack_user_id = params.dig(:event, :user)
        @slack_workspace_id = params[:team_id]
      end

      def execute
        # Legacy Slack App integrations will not yet have a token we can use
        # to call the Slack API. Do nothing, and consider the service successful.
        unless slack_installation
          logger.info(
            slack_user_id: slack_user_id,
            slack_workspace_id: slack_workspace_id,
            message: 'SlackInstallation record has no bot token'
          )

          return ServiceResponse.success
        end

        begin
          response = ::Slack::API.new(slack_installation).post(
            'views.publish',
            payload
          )
        rescue *Gitlab::HTTP::HTTP_ERRORS => e
          return ServiceResponse
            .error(message: 'HTTP exception when calling Slack API')
            .track_exception(
              as: e.class,
              slack_user_id: slack_user_id,
              slack_workspace_id: slack_workspace_id
            )
        end

        return ServiceResponse.success if response['ok']

        # For a list of errors, see:
        # https://api.slack.com/methods/views.publish#errors
        ServiceResponse.error(
          message: 'Slack API returned an error',
          payload: response
        ).track_exception(
          slack_user_id: slack_user_id,
          slack_workspace_id: slack_workspace_id,
          response: response.to_h
        )
      end

      private

      def slack_installation
        SlackIntegration.with_bot.find_by_team_id(slack_workspace_id)
      end
      strong_memoize_attr :slack_installation

      def slack_gitlab_user_connection
        ChatNames::FindUserService.new(slack_workspace_id, slack_user_id).execute
      end
      strong_memoize_attr :slack_gitlab_user_connection

      def payload
        {
          user_id: slack_user_id,
          view: ::Slack::BlockKit::AppHomeOpened.new(
            slack_user_id,
            slack_workspace_id,
            slack_gitlab_user_connection,
            slack_installation
          ).build
        }
      end

      def logger
        Gitlab::IntegrationsLogger
      end

      attr_reader :slack_user_id, :slack_workspace_id
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Integrations::SlackEvents::AppHomeOpenedService, feature_category: :integrations do
  describe '#execute' do
    let_it_be(:slack_installation) { create(:slack_integration) }

    let(:slack_workspace_id) { slack_installation.team_id }
    let(:slack_user_id) { 'U0123ABCDEF' }
    let(:api_url) { "#{Slack::API::BASE_URL}/views.publish" }
    let(:api_response) { { ok: true } }
    let(:params) do
      {
        team_id: slack_workspace_id,
        event: { user: slack_user_id },
        event_id: 'Ev03SA75UJKB'
      }
    end

    subject(:execute) { described_class.new(params).execute }

    before do
      stub_request(:post, api_url)
        .to_return(
          status: 200,
          body: api_response.to_json,
          headers: { 'Content-Type' => 'application/json' }
        )
    end

    shared_examples 'there is no bot token' do
      it 'does not call the Slack API, logs info, and returns a success response' do
        expect(Gitlab::IntegrationsLogger).to receive(:info).with(
          {
            slack_user_id: slack_user_id,
            slack_workspace_id: slack_workspace_id,
            message: 'SlackInstallation record has no bot token'
          }
        )

        is_expected.to be_success
      end
    end

    it 'calls the Slack API correctly and returns a success response' do
      mock_view = { type: 'home', blocks: [] }

      expect_next_instance_of(Slack::BlockKit::AppHomeOpened) do |ui|
        expect(ui).to receive(:build).and_return(mock_view)
      end

      is_expected.to be_success

      expect(WebMock).to have_requested(:post, api_url).with(
        body: {
          user_id: slack_user_id,
          view: mock_view
        },
        headers: {
          'Authorization' => "Bearer #{slack_installation.bot_access_token}",
          'Content-Type' => 'application/json; charset=utf-8'
        })
    end

    context 'when the slack installation is a legacy record' do
      let_it_be(:slack_installation) { create(:slack_integration, :legacy) }

      it_behaves_like 'there is no bot token'
    end

    context 'when the slack installation cannot be found' do
      let(:slack_workspace_id) { non_existing_record_id }

      it_behaves_like 'there is no bot token'
    end

    context 'when the Slack API call raises an HTTP exception' do
      before do
        allow(Gitlab::HTTP).to receive(:post).and_raise(Errno::ECONNREFUSED, 'error message')
      end

      it 'tracks the exception and returns an error response' do
        expect(::Gitlab::ErrorTracking).to receive(:track_exception)
          .with(
            Errno::ECONNREFUSED.new('HTTP exception when calling Slack API'),
            {
              slack_user_id: slack_user_id,
              slack_workspace_id: slack_workspace_id
            }
          )
        is_expected.to be_error
      end
    end

    context 'when the Slack API returns an error' do
      let(:api_response) { { ok: false, foo: 'bar' } }

      it 'tracks the exception and returns an error response' do
        expect(::Gitlab::ErrorTracking).to receive(:track_exception)
          .with(
            StandardError.new('Slack API returned an error'),
            {
              slack_user_id: slack_user_id,
              slack_workspace_id: slack_workspace_id,
              response: api_response.with_indifferent_access
            }
          )
        is_expected.to be_error
      end
    end
  end
end


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

# Returns the special URL verification response expected by Slack when the
# GitLab Slack app is first configured to receive Slack events.
#
# Slack will issue the challenge request to the endpoint that receives events
# and expect it to respond with same the `challenge` param back.
#
# See https://api.slack.com/apis/connections/events-api.
module Integrations
  module SlackEvents
    class UrlVerificationService
      def initialize(params)
        @challenge = params[:challenge]
      end

      def execute
        { challenge: challenge }
      end

      private

      attr_reader :challenge
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Integrations::SlackEvents::UrlVerificationService, feature_category: :integrations do
  describe '#execute' do
    it 'returns the challenge' do
      expect(described_class.new({ challenge: 'foo' }).execute).to eq({ challenge: 'foo' })
    end
  end
end


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

module Integrations
  module SlackInteractions
    class BlockActionService
      ALLOWED_UPDATES_HANDLERS = {
        'incident_management_project' => SlackInteractions::SlackBlockActions::IncidentManagement::ProjectUpdateHandler
      }.freeze

      def initialize(params)
        @params = params
      end

      def execute
        actions.each do |action|
          action_id = action[:action_id]

          action_handler_class = ALLOWED_UPDATES_HANDLERS[action_id]
          action_handler_class.new(params, action).execute
        end
      end

      private

      def actions
        params[:actions].select { |action| ALLOWED_UPDATES_HANDLERS[action[:action_id]] }
      end

      attr_accessor :params
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Integrations::SlackInteractions::BlockActionService, feature_category: :integrations do
  describe '#execute' do
    let_it_be(:slack_installation) { create(:slack_integration) }

    let(:params) do
      {
        view: {
          team_id: slack_installation.team_id
        },
        actions: [{
          action_id: action_id
        }]
      }
    end

    subject(:execute) { described_class.new(params).execute }

    context 'when action_id is incident_management_project' do
      let(:action_id) { 'incident_management_project' }

      it 'executes the correct handler' do
        project_handler = described_class::ALLOWED_UPDATES_HANDLERS['incident_management_project']

        expect_next_instance_of(project_handler, params, params[:actions].first) do |handler|
          expect(handler).to receive(:execute).and_return(ServiceResponse.success)
        end

        execute
      end
    end

    context 'when action_id is not known' do
      let(:action_id) { 'random' }

      it 'does not execute the handlers' do
        described_class::ALLOWED_UPDATES_HANDLERS.each_value do |handler_class|
          expect(handler_class).not_to receive(:new)
        end

        execute
      end
    end
  end
end


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

module Integrations
  module SlackInteractions
    module IncidentManagement
      class IncidentModalSubmitService
        include GitlabRoutingHelper
        include Gitlab::Routing

        IssueCreateError = Class.new(StandardError)

        def initialize(params)
          @params = params
          @values = params.dig(:view, :state, :values)
          @team_id = params.dig(:team, :id)
          @user_id = params.dig(:user, :id)
          @additional_message = ''
        end

        def execute
          create_response = Issues::CreateService.new(
            container: project,
            current_user: find_user.user,
            params: incident_params,
            perform_spam_check: false
          ).execute

          raise IssueCreateError, create_response.errors.to_sentence if create_response.error?

          incident = create_response.payload[:issue]
          incident_link = incident_link_text(incident)
          response = send_to_slack(incident_link)

          return ServiceResponse.success(payload: { incident: incident }) if response['ok']

          ServiceResponse.error(
            message: _('Something went wrong when sending the incident link to Slack.'),
            payload: response
          ).track_exception(
            response: response.to_h,
            slack_workspace_id: team_id,
            slack_user_id: user_id
          )
        rescue StandardError => e
          send_to_slack(_('There was a problem creating the incident. Please try again.'))

          ServiceResponse
            .error(
              message: e.message
            ).track_exception(
              slack_workspace_id: team_id,
              slack_user_id: user_id,
              as: e.class
            )
        end

        private

        attr_accessor :params, :values, :team_id, :user_id, :additional_message

        def incident_params
          {
            title: values.dig(:title_input, :title, :value),
            severity: severity,
            confidential: confidential?,
            description: description,
            escalation_status: { status: status },
            issue_type: "incident",
            assignee_ids: [assignee],
            label_ids: labels
          }
        end

        def strip_markup(string)
          SlackMarkdownSanitizer.sanitize(string)
        end

        def send_to_slack(text)
          response_url = params.dig(:view, :private_metadata)

          body = {
            replace_original: 'true',
            text: text
          }

          Gitlab::HTTP.post(
            response_url,
            body: Gitlab::Json.dump(body),
            headers: { 'Content-Type' => 'application/json' }
          )
        end

        def incident_link_text(incident)
          "#{_('New incident has been created')}: " \
            "<#{issue_url(incident)}|#{incident.to_reference} " \
            "- #{strip_markup(incident.title)}>. #{@additional_message}"
        end

        def project
          project_id = values.dig(
            :project_and_severity_selector,
            :incident_management_project,
            :selected_option,
            :value)

          Project.find(project_id)
        end

        def find_user
          ChatNames::FindUserService.new(team_id, user_id).execute
        end

        def description
          description =
            values.dig(:incident_description, :description, :value) ||
            values.dig(project.id.to_s.to_sym, :description, :value)

          zoom_link = values.dig(:zoom, :link, :value)

          return description if zoom_link.blank?

          "#{description} \n/zoom #{zoom_link}"
        end

        def confidential?
          values.dig(:confidentiality, :confidential, :selected_options).present?
        end

        def severity
          values.dig(:project_and_severity_selector, :severity, :selected_option, :value) || 'unknown'
        end

        def status
          values.dig(:status_and_assignee_selector, :status, :selected_option, :value)
        end

        def assignee
          assignee_id = values.dig(:status_and_assignee_selector, :assignee, :selected_option, :value)

          return unless assignee_id

          user = User.find_by_id(assignee_id)
          member = project.member(user)

          unless member
            @additional_message =
              "However, " \
              "#{user.name} was not assigned to the incident as they are not a member in #{project.name}."

            return
          end

          member.user_id
        end

        def labels
          values.dig(:label_selector, :labels, :selected_options)&.pluck(:value)
        end
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Integrations::SlackInteractions::IncidentManagement::IncidentModalSubmitService,
  feature_category: :incident_management do
  include Gitlab::Routing

  describe '#execute' do
    let_it_be(:slack_installation) { create(:slack_integration) }
    let_it_be(:project) { create(:project) }
    let_it_be(:user) { create(:user) }
    let_it_be(:api_url) { 'https://api.slack.com/id/1234' }

    let_it_be(:chat_name) do
      create(:chat_name,
        user: user,
        team_id: slack_installation.team_id,
        chat_id: slack_installation.user_id
      )
    end

    # Setting below params as they are optional, have added values wherever required in specs
    let(:zoom_link) { '' }
    let(:severity) { {} }
    let(:status) { '' }
    let(:assignee_id) { nil }
    let(:selected_label_ids) { [] }
    let(:label_ids) { { selected_options: selected_label_ids } }
    let(:confidential_selected_options) { [] }
    let(:confidential) { { selected_options: confidential_selected_options } }
    let(:title) { 'Incident title' }

    let(:zoom) do
      {
        link: {
          value: zoom_link
        }
      }
    end

    let(:params) do
      {
        team: {
          id: slack_installation.team_id
        },
        user: {
          id: slack_installation.user_id
        },
        view: {
          private_metadata: api_url,
          state: {
            values: {
              title_input: {
                title: {
                  value: title
                }
              },
              incident_description: {
                description: {
                  value: 'Incident description'
                }
              },
              project_and_severity_selector: {
                incident_management_project: {
                  selected_option: {
                    value: project.id.to_s
                  }
                },
                severity: severity
              },
              confidentiality: {
                confidential: confidential
              },
              zoom: zoom,
              status_and_assignee_selector: {
                status: {
                  selected_option: {
                    value: status
                  }
                },
                assignee: {
                  selected_option: {
                    value: assignee_id
                  }
                }
              },
              label_selector: {
                labels: label_ids
              }
            }
          }
        }
      }
    end

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

    shared_examples 'error in creation' do |error_message|
      it 'returns error and raises exception' do
        expect(::Gitlab::ErrorTracking).to receive(:track_exception)
          .with(
            described_class::IssueCreateError.new(error_message),
            {
              slack_workspace_id: slack_installation.team_id,
              slack_user_id: slack_installation.user_id
            }
          )

        expect(Gitlab::HTTP).to receive(:post)
          .with(
            api_url,
            body: Gitlab::Json.dump(
              {
                replace_original: 'true',
                text: 'There was a problem creating the incident. Please try again.'
              }
            ),
            headers: { 'Content-Type' => 'application/json' }
          )

        response = execute_service

        expect(response).to be_error
        expect(response.message).to eq(error_message)
      end
    end

    context 'when user has permissions to create incidents' do
      let(:api_response) { '{"ok":true}' }

      before do
        project.add_developer(user)
        stub_request(:post, api_url)
          .to_return(body: api_response, headers: { 'Content-Type' => 'application/json' })
      end

      context 'with markup string in title' do
        let(:title) { 'incident title' }
        let(:incident) { create(:incident, title: title, project: project) }

        before do
          allow_next_instance_of(Issues::CreateService) do |service|
            allow(service).to receive(:execute).and_return(
              ServiceResponse.success(payload: { issue: incident, error: [] })
            )
          end
        end

        it 'strips the markup and saves sends the title' do
          expect(Gitlab::HTTP).to receive(:post)
            .with(
              api_url,
              body: Gitlab::Json.dump(
                {
                  replace_original: 'true',
                  text: "New incident has been created: " \
                        "<#{issue_url(incident)}|#{incident.to_reference} - a href=\"url\"incident title/a>. "
                }
              ),
              headers: { 'Content-Type' => 'application/json' }
            ).and_return(api_response)

          execute_service
        end
      end

      context 'with non-optional params' do
        it 'creates incident' do
          response = execute_service
          incident = response[:incident]

          expect(response).to be_success
          expect(incident).not_to be_nil
          expect(incident.description).to eq('Incident description')
          expect(incident.author).to eq(user)
          expect(incident.severity).to eq('unknown')
          expect(incident.confidential).to be_falsey
          expect(incident.escalation_status).to be_triggered
        end

        it 'sends incident link to slack' do
          execute_service

          expect(WebMock).to have_requested(:post, api_url)
        end
      end

      context 'with zoom_link' do
        let(:zoom_link) { 'https://gitlab.zoom.us/j/1234' }

        it 'sets zoom link as quick action' do
          incident = execute_service[:incident]
          zoom_meeting = ZoomMeeting.find_by_issue_id(incident.id)

          expect(incident.description).to eq("Incident description")
          expect(zoom_meeting.url).to eq(zoom_link)
        end
      end

      context 'with confidential and severity' do
        let(:confidential_selected_options) { ['confidential'] }
        let(:severity) do
          {
            selected_option: {
              value: 'high'
            }
          }
        end

        it 'sets confidential and severity' do
          incident = execute_service[:incident]

          expect(incident.confidential).to be_truthy
          expect(incident.severity).to eq('high')
        end
      end

      context 'with incident status' do
        let(:status) { 'resolved' }

        it 'sets the incident status' do
          incident = execute_service[:incident]

          expect(incident.escalation_status).to be_resolved
        end
      end

      context 'with assignee id' do
        let(:assignee_id) { user.id.to_s }

        it 'assigns the incident to user' do
          incident = execute_service[:incident]

          expect(incident.assignees).to contain_exactly(user)
        end

        context 'when user is not a member of the project' do
          let(:assignee_id) { create(:user).id.to_s }

          it 'does not assign the user' do
            incident = execute_service[:incident]

            expect(incident.assignees).to be_empty
          end
        end
      end

      context 'with label ids' do
        let_it_be(:project_label1) { create(:label, project: project, title: 'Label 1') }
        let_it_be(:project_label2) { create(:label, project: project, title: 'Label 2') }

        let(:selected_label_ids) do
          [
            { value: project_label1.id.to_s },
            { value: project_label2.id.to_s }
          ]
        end

        it 'assigns the label to the incident' do
          incident = execute_service[:incident]

          expect(incident.labels).to contain_exactly(project_label1, project_label2)
        end
      end

      context 'when response is not ok' do
        let(:api_response) { '{"ok":false}' }

        it 'returns error response and tracks the exception' do
          expect(::Gitlab::ErrorTracking).to receive(:track_exception)
            .with(
              StandardError.new('Something went wrong when sending the incident link to Slack.'),
              {
                response: { 'ok' => false },
                slack_workspace_id: slack_installation.team_id,
                slack_user_id: slack_installation.user_id
              }
            )

          execute_service
        end
      end

      context 'when incident creation fails' do
        let(:title) { '' }

        it_behaves_like 'error in creation', "Title can't be blank"
      end
    end

    context 'when user does not have permission to create incidents' do
      it_behaves_like 'error in creation', 'Operation not allowed'
    end
  end
end